Components and supplies
2.5mm stereo plug
5.1V Zener diode
General Purpose Transistor NPN
Arduino Pro Mini 328 - 5V/16MHz
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
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.
1/* 2Arduino LANC<->RS232 interface 3Version 1.0 4For communicating 5 with cameras via LANC 6For the interface circuit interface see 7http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html 8 9"LANC" 10 is a registered trademark of SONY. 11CANON calls their LANC compatible port "REMOTE". 12 13Written 14 by L.Rosén 15 16------------------------------------------------------------------------------------------ 17Comments 18 regarding service mode for Sony second generation D8 camcorders: 19DCR-TRV8000E, 20 DCR-TRV8100E, DCR-TRV120E, DCR-TRV125E, DCR-TRV320E, DCR-TRV325E 21DCR-TRV420E, 22 DCR-TRV520E, DCR-TRV620E, DCR-TRV725E 23 24LANC message layout when reading/writing 25 EEPROM(8 bytes each sent with LSB first) 26B0 B1 B2 B3 B4 B5 B6 B7 27 28B0 = 29 First sent byte from our adapter 30B1 = Second sent byte from our adapter 31B2 32B3 33B4 34 = The 4 highest bits b7..b4 tells which page in the EEPROM you are at 35B5 = Confirmation 36 that the command has been received, read command confirmed with F0h, write commands 37 confirmed with F1h 38B6 = Tells which address in the EEPROM you are at 39B7 = 40 Data at address 41 42The following commands is used to navigate the EEPROM and 43 change data 44B1 B2 45FFh 00h = Read command, tells you current page:address:data 46 without changing anything 47FFh 67h = Increase page by 1 48FFh 65h = Decrase page 49 by 1 50FFh 38h = Increase address by 1 51FFh 36h = Decrase address by 1 52FFh 53 34h = Increase data by 1 54FFh 30h = Decrase data by 1 55FFh 32h = STORE command 56 57Metod 58 for checksums (PAGE:ADDRESS:DATA): 591) enable changes in memory: 00:01:00 to 00:01:01 60 (Store) 612) change data on page D, how You need (all with STORE). 623) read new 63 value: 64"xx" from 02:F0 65"yy" from 02:F1 664) enable update and visibility 67 of checksums on (0F:FE and 0F:FF): 6800:FF:00 -> 00:FF:02 (STORE) 6900:01:01 -> 70 00:01:80 (STORE) 715) update new checksums: 72write to address: 730F:FF data 74 "xx" ( from 02:F0 ) (STORE) 750F:FE data "yy" ( from 02:F1 ) (STORE) 766) 77 disable changes: 7800:FF:02 -> 00:FF:00 (STORE) 7900:01:80 -> 00:01:00 (STORE) 80 81Links 82 to more information: 83http://lea.hamradio.si/~s51kq/DV-IN.HTM 84http://www.sps.volyne.cz/set1394/anin/code20.html 85 86------------------------------------------------------------------------------------------ 87*/ 88 89// 90 The code uses fast I/O write because its time critical, 91// therefore setting 92 pins are done by writing directly to the registers: 93#define cmdPinON (PORTD = 94 B10000000) // Set digtal pin 7 (PD7) 95#define cmdPinOFF (PORTD = B00000000) 96 // Reset digtal pin 7 (PD7) 97#define ledON (PORTB = B00100000) // Set LED 98 pin 13 (PB5) 99#define ledOFF (PORTB = B00000000) // Reset LED pin 13 (PB5) 100#define 101 lancPinREAD (PINB & B00001000) // Reads pin 11 (PB3) 102#define lancPin 11 103 104int 105 bitDura = 104; // Duration of one LANC bit in microseconds, orginal 104 106int 107 halfbitDura = 52; // Half of bitDura 108byte strPointer = 0; // Index 109 when receiving chars 110char inString[5]; // A string to hold incoming 111 data 112char outString[25]; // A string to hold outgoing data 113boolean 114 strComplete = false; // Indicator to see if the string is complete 115boolean lancCmd[16]; 116 // Array for the lancCmd in bits 117boolean lancMessage[64]; // Array 118 for the complete LANC message in bits 119 120void setup() { 121 DDRD = DDRD | B10000000; 122 // Config cmdPin as output 123 DDRB = DDRB & B11110111; // Config lancPin 124 as input 125 DDRB = DDRB | B00100000; // Config ledPin as output 126 pinMode(lancPin, 127 INPUT); // Listens to the LANC line, used for pulseIn function 128 cmdPinOFF; 129 // Reset LANC control pin so that the LANC line is unaffected(HIGH) 130 131 Serial.begin(57600); // Start serial port 132 Serial.println("Welcome 133 to the Arduino LANC-RS232 interface"); 134 Serial.println("Send two bytes in hex 135 form etc. 02AF and wait for reply from camera"); 136} 137 138 139void loop() { 140 141 142 if (strComplete) { // inString has arrived 143 if (hexchartobitarray()) 144 { // Convert hex chars to bitarray 145 sendLanc(4); // 146 The LANC command needs to be repeated 4 times 147 bitarraytohexchar(); // 148 Convert received bitarray to hex chars 149 for (int i=0; i<24 ;i++) { // 150 Write back LANC message over serial 151 Serial.print(outString[i]); 152 } 153 154 Serial.print('\ 155'); 156 } 157 else { 158 Serial.println("Faulty input!"); 159 160 } 161 162 for (int i=0 ; i<5 ; i++) { // Clear input array 163 inString[i] 164 = 0; 165 } 166 strComplete = false; // Reset data received 167 flag 168 } 169 170} 171 172 173void bitarraytohexchar() { 174 // The bit array 175 lancMessage contains the whole LANC message (8 bytes) with LSB first 176 // This 177 function converts them to hex chars and stores them in outString (16 chars) 178 179 180 byte temp = 0; 181 182 for ( int i=0 ; i<8 ; i++) { // Byte loop 183 184 185 for ( int j=0 ; j<4 ; j++) { // Bit loop 186 temp += (pow2(j) * lancMessage[(j+4)+i*8]); 187 188 } 189 outString[i*3] = bytetohexchar(temp); 190 temp = 0; 191 192 for 193 ( int j=0 ; j<4 ; j++) { // Bit loop 194 temp += (pow2(j) * lancMessage[j+i*8]); 195 196 } 197 outString[i*3+1] = bytetohexchar(temp); 198 outString[i*3+2] = ' '; 199 200 temp = 0; 201 } 202 203 outString[24] = '\ 204'; 205 206} 207 208 209boolean 210 hexchartobitarray() { 211 // The hex code in char (4 chars) is located in inString 212 213 // This function fills the lancCmd array with the bits in the order they should 214 be sent 215 // First byte 1 then byte 2 but with LSB first for both bytes 216 217 218 int byte1, byte2; 219 220 for (int i = 0 ; i < 4 ; i++ ) { 221 if (!(isHexadecimalDigit(inString[i]))) 222 { 223 return 0; 224 } 225 } 226 227 byte1 = (hexchartoint(inString[0]) << 4) 228 + hexchartoint(inString[1]); 229 byte2 = (hexchartoint(inString[2]) << 4) + hexchartoint(inString[3]); 230 231 232 for (int i = 0 ; i < 8 ; i++ ) { 233 lancCmd[i] = bitRead(byte1,i); // Reads 234 one bit from a number, x is number, n is position (0 is LSB) 235 } 236 for (int 237 i = 0 ; i < 8 ; i++ ) { 238 lancCmd[i + 8] = bitRead(byte2,i); // Reads one 239 bit from a number, x is number, n is position (0 is LSB) 240 } 241 242 return 1; 243} 244 245 246void 247 sendLanc(byte repeats) { 248 // This function is time critical and optimized for 249 Arduino Pro Mini 250 // It takes ~3.2us for the arduino to set a pin state with 251 the digitalWrite command 252 // It takes ~80ns for the arduino to set pin state 253 using the direct register method 254 // delayMicroseconds(50) ~ 49us, delayMicroseconds(100) 255 ~ 99us 256 257 int i = 0; 258 int bytenr = 0; 259 260 while (pulseIn(lancPin, 261 HIGH) < 5000) { 262 // Sync to next LANC message 263 // "pulseIn, HIGH" 264 catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V 265 266 // "pulseIn" also returns the pulse duration so we can check if the previous 267 +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet 268 269 } 270 271 while (repeats) { 272 273 i = 0; 274 bytenr = 0; 275 276 277 ledON; // LANC message LED indicator on 278 279 280 281 for ( ; bytenr<8 ; bytenr++) { 282 delayMicroseconds(bitDura-7); // 283 LOW after long pause means the START bit of Byte 0 is here, wait START bit duration 284 285 for ( ; i<(8*(bytenr+1)) ; i++) { 286 if (bytenr<2) { 287 if 288 (lancCmd[i]) { // During the first two bytes the adapter controls 289 the line and puts out data 290 cmdPinON; 291 292 } 293 else { 294 cmdPinOFF; 295 } 296 } 297 298 delayMicroseconds(halfbitDura); 299 lancMessage[i] = !lancPinREAD; 300 // Read data line during middle of bit 301 delayMicroseconds(halfbitDura); 302 303 } 304 cmdPinOFF; 305 if (bytenr == 7) { 306 ledOFF; 307 } 308 309 delayMicroseconds(halfbitDura); // Make sure to be in the stop bit 310 before waiting for next byte 311 while (lancPinREAD) { // 312 Loop as long as the LANC line is +5V during the stop bit or between messages 313 314 } 315 } 316 repeats--; 317 } 318} 319 320 321/* 322 323 SerialEvent occurs whenever a new data comes in the 324 hardware serial RX. This 325 routine is run between each 326 time loop() runs, so using delay inside loop can 327 delay 328 response. Multiple bytes of data may be available. 329 */ 330void serialEvent() 331 { 332 while (Serial.available()) { 333 char inChar = (char)Serial.read(); // 334 Get the new byte 335 inString[strPointer++] = inChar; // 336 Add it to the input string 337 if ((inChar == '\ 338') || (inChar == '\ ') || (strPointer 339 > 4)) { // If the incoming character is a newline, carriage return or 4 bytes has 340 been received flag so the main loop can act 341 strComplete = true; 342 strPointer 343 = 0; 344 } 345 } 346} 347 348 349int pow2(int x) { 350 switch (x) { 351 case 352 0: 353 return 1; 354 break; 355 case 1: 356 return 2; 357 358 break; 359 case 2: 360 return 4; 361 break; 362 case 363 3: 364 return 8; 365 break; 366 case 4: 367 return 16; 368 369 break; 370 case 5: 371 return 32; 372 break; 373 case 374 6: 375 return 64; 376 break; 377 case 7: 378 return 128; 379 380 break; 381 default: 382 return 0; 383 break; 384 } 385} 386 387 388char 389 bytetohexchar(byte hexbyte) { 390 switch (hexbyte) { 391 case 15: 392 return 393 'F'; 394 break; 395 case 14: 396 return 'E'; 397 break; 398 case 399 13: 400 return 'D'; 401 break; 402 case 12: 403 return 'C'; 404 405 break; 406 case 11: 407 return 'B'; 408 break; 409 case 10: 410 411 return 'A'; 412 break; 413 default: 414 return (hexbyte + 48); 415 416 break; 417 } 418} 419 420 421int hexchartoint(char hexchar) { 422 switch (hexchar) 423 { 424 case 'F': 425 return 15; 426 break; 427 case 'f': 428 return 429 15; 430 break; 431 case 'E': 432 return 14; 433 break; 434 case 435 'e': 436 return 14; 437 break; 438 case 'D': 439 return 13; 440 441 break; 442 case 'd': 443 return 13; 444 break; 445 case 'C': 446 447 return 12; 448 break; 449 case 'c': 450 return 12; 451 break; 452 453 case 'B': 454 return 11; 455 break; 456 case 'b': 457 return 11; 458 459 break; 460 case 'A': 461 return 10; 462 break; 463 case 'a': 464 465 return 10; 466 break; 467 default: 468 return (int) (hexchar - 48); 469 470 break; 471 } 472} 473 474
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.
1/* 2Arduino LANC<->RS232 interface 3Version 1.0 4For communicating with cameras via LANC 5For the interface circuit interface see 6http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html 7 8"LANC" is a registered trademark of SONY. 9CANON calls their LANC compatible port "REMOTE". 10 11Written by L.Rosén 12 13------------------------------------------------------------------------------------------ 14Comments regarding service mode for Sony second generation D8 camcorders: 15DCR-TRV8000E, DCR-TRV8100E, DCR-TRV120E, DCR-TRV125E, DCR-TRV320E, DCR-TRV325E 16DCR-TRV420E, DCR-TRV520E, DCR-TRV620E, DCR-TRV725E 17 18LANC message layout when reading/writing EEPROM(8 bytes each sent with LSB first) 19B0 B1 B2 B3 B4 B5 B6 B7 20 21B0 = First sent byte from our adapter 22B1 = Second sent byte from our adapter 23B2 24B3 25B4 = The 4 highest bits b7..b4 tells which page in the EEPROM you are at 26B5 = Confirmation that the command has been received, read command confirmed with F0h, write commands confirmed with F1h 27B6 = Tells which address in the EEPROM you are at 28B7 = Data at address 29 30The following commands is used to navigate the EEPROM and change data 31B1 B2 32FFh 00h = Read command, tells you current page:address:data without changing anything 33FFh 67h = Increase page by 1 34FFh 65h = Decrase page by 1 35FFh 38h = Increase address by 1 36FFh 36h = Decrase address by 1 37FFh 34h = Increase data by 1 38FFh 30h = Decrase data by 1 39FFh 32h = STORE command 40 41Metod for checksums (PAGE:ADDRESS:DATA): 421) enable changes in memory: 00:01:00 to 00:01:01 (Store) 432) change data on page D, how You need (all with STORE). 443) read new value: 45"xx" from 02:F0 46"yy" from 02:F1 474) enable update and visibility of checksums on (0F:FE and 0F:FF): 4800:FF:00 -> 00:FF:02 (STORE) 4900:01:01 -> 00:01:80 (STORE) 505) update new checksums: 51write to address: 520F:FF data "xx" ( from 02:F0 ) (STORE) 530F:FE data "yy" ( from 02:F1 ) (STORE) 546) disable changes: 5500:FF:02 -> 00:FF:00 (STORE) 5600:01:80 -> 00:01:00 (STORE) 57 58Links to more information: 59http://lea.hamradio.si/~s51kq/DV-IN.HTM 60http://www.sps.volyne.cz/set1394/anin/code20.html 61 62------------------------------------------------------------------------------------------ 63*/ 64 65// The code uses fast I/O write because its time critical, 66// therefore setting pins are done by writing directly to the registers: 67#define cmdPinON (PORTD = B10000000) // Set digtal pin 7 (PD7) 68#define cmdPinOFF (PORTD = B00000000) // Reset digtal pin 7 (PD7) 69#define ledON (PORTB = B00100000) // Set LED pin 13 (PB5) 70#define ledOFF (PORTB = B00000000) // Reset LED pin 13 (PB5) 71#define lancPinREAD (PINB & B00001000) // Reads pin 11 (PB3) 72#define lancPin 11 73 74int bitDura = 104; // Duration of one LANC bit in microseconds, orginal 104 75int halfbitDura = 52; // Half of bitDura 76byte strPointer = 0; // Index when receiving chars 77char inString[5]; // A string to hold incoming data 78char outString[25]; // A string to hold outgoing data 79boolean strComplete = false; // Indicator to see if the string is complete 80boolean lancCmd[16]; // Array for the lancCmd in bits 81boolean lancMessage[64]; // Array for the complete LANC message in bits 82 83void setup() { 84 DDRD = DDRD | B10000000; // Config cmdPin as output 85 DDRB = DDRB & B11110111; // Config lancPin as input 86 DDRB = DDRB | B00100000; // Config ledPin as output 87 pinMode(lancPin, INPUT); // Listens to the LANC line, used for pulseIn function 88 cmdPinOFF; // Reset LANC control pin so that the LANC line is unaffected(HIGH) 89 Serial.begin(57600); // Start serial port 90 Serial.println("Welcome to the Arduino LANC-RS232 interface"); 91 Serial.println("Send two bytes in hex form etc. 02AF and wait for reply from camera"); 92} 93 94 95void loop() { 96 97 if (strComplete) { // inString has arrived 98 if (hexchartobitarray()) { // Convert hex chars to bitarray 99 sendLanc(4); // The LANC command needs to be repeated 4 times 100 bitarraytohexchar(); // Convert received bitarray to hex chars 101 for (int i=0; i<24 ;i++) { // Write back LANC message over serial 102 Serial.print(outString[i]); 103 } 104 Serial.print('\n'); 105 } 106 else { 107 Serial.println("Faulty input!"); 108 } 109 110 for (int i=0 ; i<5 ; i++) { // Clear input array 111 inString[i] = 0; 112 } 113 strComplete = false; // Reset data received flag 114 } 115 116} 117 118 119void bitarraytohexchar() { 120 // The bit array lancMessage contains the whole LANC message (8 bytes) with LSB first 121 // This function converts them to hex chars and stores them in outString (16 chars) 122 123 byte temp = 0; 124 125 for ( int i=0 ; i<8 ; i++) { // Byte loop 126 127 for ( int j=0 ; j<4 ; j++) { // Bit loop 128 temp += (pow2(j) * lancMessage[(j+4)+i*8]); 129 } 130 outString[i*3] = bytetohexchar(temp); 131 temp = 0; 132 133 for ( int j=0 ; j<4 ; j++) { // Bit loop 134 temp += (pow2(j) * lancMessage[j+i*8]); 135 } 136 outString[i*3+1] = bytetohexchar(temp); 137 outString[i*3+2] = ' '; 138 temp = 0; 139 } 140 141 outString[24] = '\n'; 142 143} 144 145 146boolean hexchartobitarray() { 147 // The hex code in char (4 chars) is located in inString 148 // This function fills the lancCmd array with the bits in the order they should be sent 149 // First byte 1 then byte 2 but with LSB first for both bytes 150 151 int byte1, byte2; 152 153 for (int i = 0 ; i < 4 ; i++ ) { 154 if (!(isHexadecimalDigit(inString[i]))) { 155 return 0; 156 } 157 } 158 159 byte1 = (hexchartoint(inString[0]) << 4) + hexchartoint(inString[1]); 160 byte2 = (hexchartoint(inString[2]) << 4) + hexchartoint(inString[3]); 161 162 for (int i = 0 ; i < 8 ; i++ ) { 163 lancCmd[i] = bitRead(byte1,i); // Reads one bit from a number, x is number, n is position (0 is LSB) 164 } 165 for (int i = 0 ; i < 8 ; i++ ) { 166 lancCmd[i + 8] = bitRead(byte2,i); // Reads one bit from a number, x is number, n is position (0 is LSB) 167 } 168 169 return 1; 170} 171 172 173void sendLanc(byte repeats) { 174 // This function is time critical and optimized for Arduino Pro Mini 175 // It takes ~3.2us for the arduino to set a pin state with the digitalWrite command 176 // It takes ~80ns for the arduino to set pin state using the direct register method 177 // delayMicroseconds(50) ~ 49us, delayMicroseconds(100) ~ 99us 178 179 int i = 0; 180 int bytenr = 0; 181 182 while (pulseIn(lancPin, HIGH) < 5000) { 183 // Sync to next LANC message 184 // "pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V 185 // "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 186 } 187 188 while (repeats) { 189 190 i = 0; 191 bytenr = 0; 192 193 ledON; // LANC message LED indicator on 194 195 196 for ( ; bytenr<8 ; bytenr++) { 197 delayMicroseconds(bitDura-7); // LOW after long pause means the START bit of Byte 0 is here, wait START bit duration 198 for ( ; i<(8*(bytenr+1)) ; i++) { 199 if (bytenr<2) { 200 if (lancCmd[i]) { // During the first two bytes the adapter controls the line and puts out data 201 cmdPinON; 202 } 203 else { 204 cmdPinOFF; 205 } 206 } 207 delayMicroseconds(halfbitDura); 208 lancMessage[i] = !lancPinREAD; // Read data line during middle of bit 209 delayMicroseconds(halfbitDura); 210 } 211 cmdPinOFF; 212 if (bytenr == 7) { 213 ledOFF; 214 } 215 delayMicroseconds(halfbitDura); // Make sure to be in the stop bit before waiting for next byte 216 while (lancPinREAD) { // Loop as long as the LANC line is +5V during the stop bit or between messages 217 } 218 } 219 repeats--; 220 } 221} 222 223 224/* 225 SerialEvent occurs whenever a new data comes in the 226 hardware serial RX. This routine is run between each 227 time loop() runs, so using delay inside loop can delay 228 response. Multiple bytes of data may be available. 229 */ 230void serialEvent() { 231 while (Serial.available()) { 232 char inChar = (char)Serial.read(); // Get the new byte 233 inString[strPointer++] = inChar; // Add it to the input string 234 if ((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 act 235 strComplete = true; 236 strPointer = 0; 237 } 238 } 239} 240 241 242int pow2(int x) { 243 switch (x) { 244 case 0: 245 return 1; 246 break; 247 case 1: 248 return 2; 249 break; 250 case 2: 251 return 4; 252 break; 253 case 3: 254 return 8; 255 break; 256 case 4: 257 return 16; 258 break; 259 case 5: 260 return 32; 261 break; 262 case 6: 263 return 64; 264 break; 265 case 7: 266 return 128; 267 break; 268 default: 269 return 0; 270 break; 271 } 272} 273 274 275char bytetohexchar(byte hexbyte) { 276 switch (hexbyte) { 277 case 15: 278 return 'F'; 279 break; 280 case 14: 281 return 'E'; 282 break; 283 case 13: 284 return 'D'; 285 break; 286 case 12: 287 return 'C'; 288 break; 289 case 11: 290 return 'B'; 291 break; 292 case 10: 293 return 'A'; 294 break; 295 default: 296 return (hexbyte + 48); 297 break; 298 } 299} 300 301 302int hexchartoint(char hexchar) { 303 switch (hexchar) { 304 case 'F': 305 return 15; 306 break; 307 case 'f': 308 return 15; 309 break; 310 case 'E': 311 return 14; 312 break; 313 case 'e': 314 return 14; 315 break; 316 case 'D': 317 return 13; 318 break; 319 case 'd': 320 return 13; 321 break; 322 case 'C': 323 return 12; 324 break; 325 case 'c': 326 return 12; 327 break; 328 case 'B': 329 return 11; 330 break; 331 case 'b': 332 return 11; 333 break; 334 case 'A': 335 return 10; 336 break; 337 case 'a': 338 return 10; 339 break; 340 default: 341 return (int) (hexchar - 48); 342 break; 343 } 344} 345 346
Downloadable files
Arduino-LANC HW interface
All the hardware you need for this project, you can skip the push button (not used). The NPN transistor can be almost any small-signal type.
Arduino-LANC HW interface
Comments
Only logged in users can leave comments
L-Rosen
0 Followers
•0 Projects
+2
Work attribution
Table of contents
Intro
4
0