├── .gitignore ├── common.cpp ├── README.markdown ├── typedef.h ├── spi.cpp ├── common.h ├── fakelens.cpp └── fakebody.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .cproject 2 | .project 3 | .settings 4 | -------------------------------------------------------------------------------- /common.cpp: -------------------------------------------------------------------------------- 1 | /* common.cpp 2 | * Bits of helper code common to the lens and body faking code. 3 | */ 4 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | The object of this project is to decode enough of the micro four thirds (MFT) lens-body communication protocol to be able to use MFT lenses on the Frankencamera F4. 2 | 3 | So far, Steven Bell has worked on this using a PC logic analyzer to watch the commands going between the body and lens, and by using an Arduino to drive the lens. 4 | 5 | The code in the repository is written for an Arduino Mega 2560. 6 | 7 | -------------------------------------------------------------------------------- /typedef.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file typedef.h 3 | * Type definitions for integer and floating point variables. 4 | * 5 | * \author Steven Bell 6 | * \date 22 July 2010 7 | */ 8 | 9 | #ifndef TYPEDEF_H_ 10 | #define TYPEDEF_H_ 11 | 12 | #include 13 | 14 | typedef uint8_t uint8; ///< 8-bit unsigned value 15 | typedef int8_t int8; ///< 8-bit signed value 16 | typedef uint16_t uint16; ///< 16-bit unsigned value 17 | typedef int16_t int16; ///< 16-bit signed value 18 | typedef uint32_t uint32; ///< 32-bit unsigned value 19 | typedef int32_t int32; ///< 32-bit signed value 20 | typedef uint64_t uint64; ///< 64-bit unsigned value 21 | typedef int64_t int64; ///< 64-bit signed value 22 | 23 | /** 24 | * \brief 32-bit floating-point value 25 | * 26 | * Both floats and doubles are 32-bit floating point values, so 27 | * there is no float64. 28 | */ 29 | typedef float float32; 30 | 31 | #endif /* TYPEDEF_H_ */ 32 | -------------------------------------------------------------------------------- /spi.cpp: -------------------------------------------------------------------------------- 1 | /* spi.cpp 2 | * Code to use the SPI hardware on the Atmega 2560 for communication with 3 | * the camera body or lens, rather than bit-banging. 4 | * Steven Bell 5 | * 3 October 2012 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "typedef.h" 10 | 11 | // Pins: 12 | #define PIN_MISO 50 // Master out, slave in 13 | #define PIN_MOSI 51 // Master in, slave out 14 | #define PIN_CLK 52 // Clock, driven by master 15 | #define PIN_SS 53 // When low, the slave SPI is enabled 16 | 17 | int main() 18 | { 19 | init(); 20 | 21 | 22 | // Configuration: 23 | pinMode(PIN_CLK, OUTPUT); // Set CLK as an output 24 | pinMode(PIN_SS, OUTPUT); // Don't use SS, so force it as an output 25 | 26 | // Set the SPI hardware to master mode 27 | // SPE - Enable 28 | // DORD - Set data order to LSB-first 29 | // MSTR - Master mode 30 | // CPOL - Set clock polarity to "normally high" 31 | // CPHA - Set to read on trailing (rising) edge 32 | // SPR1 - Set clock frequency to 1/64 Fosc (but doubled below) 33 | 34 | SPCR = (1< 5 | * 26 September 2012 6 | */ 7 | 8 | /* Pin numbers refer to the labels on the Arduino Mega 2560 board. These 9 | * numbers are used with the Arduino library. 10 | * 11 | * PORTX and PINX refer to the registers which correspond to those pins. 12 | * PORT holds output values, PIN holds input values. 13 | */ 14 | 15 | #define SLEEP 45 // Port L 4 16 | #define BODY_ACK 46 // Port L 3 17 | #define BODY_ACK_PIN PINL 18 | #define BODY_ACK_PORT PORTL 19 | 20 | #define LENS_ACK 47 // Port L 2 21 | #define LENS_ACK_PORT PORTL 22 | #define LENS_ACK_PIN PINL 23 | 24 | #define CLK 52 // Port B 1 25 | #define CLK_PORT PORTB 26 | #define CLK_PIN PINB 27 | 28 | // Since the camera has only a single data line, MOSI and MISO are tied 29 | // together externally. For bit-banging, we'll just use MISO. 30 | #define DATA_MISO 50 // Port B 3 31 | #define DATA_MOSI 51 // Port B 2 32 | #define DATA DATA_MISO 33 | 34 | #define DATA_PORT PORTB 35 | #define DATA_PIN PINB // PIN holds inputs 36 | #define DATA_DIR DDRB 37 | 38 | #define FOCUS 49 // Port L 0 39 | #define SHUTTER 48 // Port L 1 40 | 41 | #define SPI_SS 53 // When low, the slave SPI is enabled 42 | 43 | // Useful bitmasks for manipulating the IO pins 44 | // Bitwise OR these with port registers to set pins high, or 45 | // bitwise AND these with pin registers to read the pin. 46 | const uint8 CLK_HIGH = 0b00000010; // Port B 1 47 | const uint8 DATA_MOSI_HIGH = 0b00000100; // Port B 2 48 | const uint8 DATA_MISO_HIGH = 0b00001000; // Port B 3 49 | #define DATA_HIGH DATA_MISO_HIGH 50 | 51 | const uint8 LENS_ACK_HIGH = 0b00000100; // Port L 2 52 | const uint8 BODY_ACK_HIGH = 0b00001000; // Port L 3 53 | 54 | // Bitwise AND these with port registers to set pins low 55 | const uint8 CLK_LOW = ~CLK_HIGH; 56 | const uint8 DATA_LOW = ~DATA_HIGH; 57 | const uint8 LENS_ACK_LOW = ~LENS_ACK_HIGH; 58 | const uint8 BODY_ACK_LOW = ~BODY_ACK_HIGH; 59 | 60 | // Bitwise OR these with port DDR registers to set outputs 61 | const uint8 CLK_WRITE = 0b00000010; // Port B 1 62 | const uint8 DATA_MOSI_WRITE = 0b00000100; // Port B 2 63 | const uint8 DATA_MISO_WRITE = 0b00001000; // Port B 3 64 | #define DATA_WRITE DATA_MISO_WRITE 65 | 66 | // Bitwise AND these with port DDR registers to set inputs 67 | const uint8 DATA_READ = ~DATA_WRITE; 68 | -------------------------------------------------------------------------------- /fakelens.cpp: -------------------------------------------------------------------------------- 1 | /* fakelens.cpp 2 | * Code that pretends to be a lens and talks to the body. 3 | * Steven Bell 4 | * 27 September 2012 5 | */ 6 | 7 | #include "Arduino.h" 8 | #include "typedef.h" 9 | #include "common.h" 10 | 11 | /* Performs one-time pin initialization and other setup. The pin directions 12 | * here are the opposite of fakebody, since we're playing the other side. */ 13 | void setup() { 14 | Serial.begin(115200); 15 | pinMode(SLEEP, INPUT); 16 | pinMode(BODY_ACK, INPUT); 17 | pinMode(LENS_ACK, OUTPUT); 18 | pinMode(FOCUS, INPUT); 19 | pinMode(SHUTTER, INPUT); 20 | digitalWrite(FOCUS, LOW); // Turn off the pull-ups just to be sure 21 | digitalWrite(SHUTTER, LOW); 22 | 23 | // Configure the SPI hardware 24 | // SPE - Enable 25 | // DORD - Set data order to LSB-first 26 | // Slave mode (Master bit is not set) 27 | // CPOL - Set clock polarity to "normally high" 28 | // CPHA - Set to read on trailing (rising) edge 29 | SPCR = (1< 4 | * August 2012 5 | */ 6 | 7 | #include "Arduino.h" 8 | #include "typedef.h" 9 | #include "common.h" 10 | 11 | // Number of bytes in a standby response packet 12 | #define STANDBY_RESPONSE_BYTES 31 13 | 14 | /* Performs one-time pin initialization and other setup */ 15 | void setup() { 16 | Serial.begin(115200); 17 | pinMode(SLEEP, OUTPUT); 18 | pinMode(BODY_ACK, OUTPUT); 19 | pinMode(LENS_ACK, INPUT); 20 | pinMode(CLK, OUTPUT); 21 | pinMode(DATA_MISO, OUTPUT); 22 | pinMode(DATA_MOSI, INPUT); // We're only using MISO, but they're tied together. 23 | pinMode(FOCUS, OUTPUT); 24 | pinMode(SHUTTER, OUTPUT); 25 | 26 | digitalWrite(SLEEP, LOW); 27 | digitalWrite(BODY_ACK, LOW); 28 | digitalWrite(CLK, HIGH); 29 | } 30 | 31 | /* Writes a single byte on the SPI bus at about 500 kHz, and waits for the 32 | * camera acknowledgment. 33 | * The clock and data pins are set to be outputs 34 | * The data is written LSB-first. */ 35 | void writeByte(uint8 value) 36 | { 37 | DATA_DIR |= DATA_WRITE; // Just in case... 38 | DATA_DIR |= CLK_WRITE; 39 | // Data is set on the falling edge, and the lens reads it on the rising edge 40 | for(uint8 i = 0; i < 8; i++){ 41 | CLK_PORT &= CLK_LOW; // Set the clock pin low 42 | if(value & 0x01){ // Set the data pin to the bit value 43 | DATA_PORT |= DATA_HIGH; 44 | } 45 | else{ 46 | DATA_PORT &= DATA_LOW; 47 | } 48 | CLK_PORT |= CLK_HIGH; // Set the clock pin high 49 | value = value >> 1; // Shift down to the next bit 50 | } 51 | // Wait for the ACK 52 | delayMicroseconds(15); 53 | } 54 | 55 | /* Reads a single byte from the SPI bus. 56 | * Data is read LSB-first 57 | */ 58 | unsigned char readByte() 59 | { 60 | unsigned char value = 0; 61 | for(int i = 0; i < 8; i++){ 62 | CLK_PORT &= CLK_LOW; 63 | value = value >> 1; 64 | CLK_PORT |= CLK_HIGH; 65 | if(DATA_PIN & DATA_HIGH){ 66 | value |= 0x80; 67 | } 68 | } 69 | return(value); 70 | } 71 | 72 | // Wait for a falling edge on the lens ACK pin 73 | inline void waitLensFall() 74 | { 75 | while(!(LENS_ACK_PIN & LENS_ACK_HIGH)){} // Wait until it's high first 76 | while(LENS_ACK_PIN & LENS_ACK_HIGH){} 77 | } 78 | 79 | // Wait for a rising edge on the lens ACK pin 80 | inline void waitLensRise() 81 | { 82 | while(LENS_ACK_PIN & LENS_ACK_HIGH){} // Wait until it's low first 83 | while(!(LENS_ACK_PIN & LENS_ACK_HIGH)){} 84 | } 85 | 86 | // Wait until the lens ACK pin is high 87 | inline void waitLensHigh() 88 | { 89 | while(!(LENS_ACK_PIN & LENS_ACK_HIGH)){} 90 | } 91 | 92 | // Wait until the lens ACK pin is low 93 | inline void waitLensLow() 94 | { 95 | while((LENS_ACK_PIN & LENS_ACK_HIGH)){} 96 | } 97 | 98 | /* Sends a 4-byte command and waits for the checksum 99 | * Returns true if the checksum matches, false otherwise. 100 | * The BODY_ACK pin should be low when this method enters. 101 | * The BODY_ACK pin is low when this method exits. */ 102 | bool sendCommand(uint8* bytes) 103 | { 104 | uint8 checksum = 0; // Our running checksum 105 | uint8 checkbyte; // Checksum from the lens 106 | 107 | digitalWrite(BODY_ACK, HIGH); // Get the lens' attention 108 | waitLensHigh(); // Wait for it to be ready 109 | 110 | // Send the four bytes 111 | for(uint8 i = 0; i < 4; i++){ 112 | writeByte(bytes[i]); 113 | checksum += bytes[i]; 114 | } 115 | 116 | pinMode(DATA, INPUT); // Relinquish control of the data pin 117 | 118 | waitLensLow(); 119 | digitalWrite(BODY_ACK, LOW); 120 | waitLensHigh(); 121 | digitalWrite(BODY_ACK, HIGH); // Tell the lens we're ready 122 | 123 | checkbyte = readByte(); 124 | 125 | digitalWrite(BODY_ACK, LOW); 126 | 127 | return(checksum == checkbyte); 128 | } 129 | 130 | /* Reads a series of bytes in response to a command 131 | * bytes - Pointer to store the byte values in. 132 | * maxBytes - Maximum number of bytes to read, not including header. 133 | * Returns true if expected number of bytes is read, false otherwise. */ 134 | uint16 readBytes(uint8* bytes, uint16 maxBytes) 135 | { 136 | // Read the packet length 137 | uint16 nBytes; 138 | 139 | waitLensHigh(); 140 | digitalWrite(BODY_ACK, HIGH); 141 | nBytes = readByte(); // Low 8 bits 142 | BODY_ACK_PORT &= BODY_ACK_LOW; 143 | 144 | delayMicroseconds(10); 145 | waitLensHigh(); 146 | 147 | digitalWrite(BODY_ACK, HIGH); 148 | nBytes += (uint16)readByte() << 8; // High 8 bits 149 | digitalWrite(BODY_ACK, LOW); 150 | 151 | waitLensLow(); // Just to be safe 152 | 153 | // If the lens is trying to give us more bytes than we have storage for, fail. 154 | if(nBytes > maxBytes){ 155 | return(0); 156 | } 157 | 158 | for(uint16 i = 0; i < nBytes; i++){ 159 | waitLensHigh(); 160 | digitalWrite(BODY_ACK, HIGH); 161 | bytes[i] = readByte(); 162 | //BODY_ACK_PORT &= BODY_ACK_LOW; // Set low; digitalWrite is too slow here. 163 | digitalWrite(BODY_ACK, LOW); 164 | // BUG: something isn't working with waitLensLow. 165 | //waitLensLow(); 166 | delayMicroseconds(10); 167 | } 168 | 169 | return(nBytes); 170 | } 171 | 172 | void powerup() { 173 | uint8 bytedump[50]; // Array for dumping bytes read from the lens 174 | 175 | // Powerup 176 | digitalWrite(SLEEP, HIGH); 177 | delay(10); 178 | digitalWrite(BODY_ACK, HIGH); 179 | 180 | waitLensFall(); 181 | digitalWrite(BODY_ACK, LOW); 182 | 183 | delay(20); 184 | 185 | // Now start some data transfer 186 | uint8 c1[4] = {0xB0, 0xF2, 0x00, 0x00}; 187 | sendCommand(c1); 188 | 189 | // There seems to be an extra low-high here, not sure why 190 | waitLensLow(); 191 | digitalWrite(BODY_ACK, HIGH); 192 | waitLensFall(); // Wait for rise and fall 193 | digitalWrite(BODY_ACK, LOW); 194 | digitalWrite(BODY_ACK, HIGH); 195 | 196 | readByte(); // Should be 0x00? 197 | digitalWrite(BODY_ACK, LOW); // Tell the lens we're working 198 | 199 | delay(1); 200 | 201 | uint8 c2[4] = {0xC0, 0xF6, 0x00, 0x00}; 202 | sendCommand(c2); 203 | readBytes(bytedump, 5); 204 | 205 | 206 | delay(1); 207 | 208 | uint8 c3[4] = {0xA0, 0xF5, 0x01, 0x00}; 209 | sendCommand(c3); 210 | 211 | // This is where the camera does a clock reset. Is that important? 212 | delay(1); 213 | 214 | uint8 c4[4] = {0xC1, 0xF9, 0x00, 0x00}; 215 | sendCommand(c4); 216 | 217 | readBytes(bytedump, 0x15); // Read 21 bytes 218 | 219 | delay(1); 220 | 221 | uint8 c5[4] = {0x60, 0xF0, 0x00, 0x00}; 222 | sendCommand(c5); 223 | 224 | digitalWrite(BODY_ACK, HIGH); 225 | waitLensHigh(); 226 | // Old lens had different commands; not sure what these are. 227 | writeByte(0x05); 228 | writeByte(0x00); 229 | writeByte(0x00); 230 | writeByte(0x00); 231 | writeByte(0x00); 232 | writeByte(0x00); 233 | 234 | // Read one byte 235 | pinMode(DATA, INPUT); 236 | digitalWrite(BODY_ACK, LOW); 237 | waitLensRise(); 238 | digitalWrite(BODY_ACK, HIGH); 239 | readByte(); 240 | digitalWrite(BODY_ACK, LOW); 241 | 242 | // Standby packet 243 | uint8 c6[4] = {0xC1, 0x80, 0x01, 0x06}; 244 | sendCommand(c6); 245 | readBytes(bytedump, 0x1F); // Read 31 bytes 246 | 247 | delay(1); 248 | 249 | // Manual focus 250 | uint8 c7[4] = {0xA0, 0xB0, 0xFE, 0x00}; // Ring forward 251 | //uint8 c7[4] = {0xA0, 0xB0, 0xFE, 0x01}; // Ring reverse 252 | sendCommand(c7); 253 | 254 | delay(1); 255 | 256 | uint8 c8[4] = {0xB1, 0x88, 0x03, 0x02}; 257 | sendCommand(c8); 258 | // There's something funny here - an extra handshake on the ACK lines, and then a single byte 259 | // Assume at this point that our ACK line is low 260 | waitLensLow(); 261 | digitalWrite(BODY_ACK, HIGH); 262 | // Lens goes high and then low again 263 | waitLensFall(); 264 | digitalWrite(BODY_ACK, LOW); 265 | waitLensHigh(); 266 | digitalWrite(BODY_ACK, HIGH); 267 | readByte(); // This should be zero 268 | 269 | 270 | digitalWrite(BODY_ACK, LOW); // Clean up after ourselves 271 | delay(1); 272 | } 273 | 274 | void standbyPacket(uint8* response) 275 | { 276 | uint8 standbyRequest[] = {0xC1, 0x80, 0x01, 0x06}; 277 | sendCommand(standbyRequest); 278 | waitLensLow(); // BUG: Hangs here if the function return doesn't happen fast enough 279 | readBytes(response, STANDBY_RESPONSE_BYTES); 280 | 281 | // Print all of the bytes, skipping the checksum at the end 282 | /* 283 | for(uint8 i = 0; i < STANDBY_RESPONSE_BYTES -1; i++){ 284 | Serial.print(response[i]); 285 | Serial.print(" "); 286 | } 287 | Serial.print('\n'); 288 | */ 289 | 290 | } 291 | 292 | void extendedPacket(uint8 data[17]) 293 | { 294 | digitalWrite(BODY_ACK, HIGH); 295 | waitLensHigh(); 296 | 297 | // Write 4 bytes 298 | writeByte(data[0]); 299 | writeByte(data[1]); 300 | writeByte(data[2]); 301 | writeByte(data[3]); 302 | delayMicroseconds(100); 303 | 304 | // Read one byte 305 | pinMode(DATA, INPUT); 306 | digitalWrite(BODY_ACK, LOW); 307 | waitLensRise(); 308 | digitalWrite(BODY_ACK, HIGH); 309 | data[4] = readByte(); 310 | 311 | digitalWrite(BODY_ACK, LOW); 312 | // We really should wait for the lens to be low here 313 | delayMicroseconds(250); 314 | digitalWrite(BODY_ACK, HIGH); 315 | waitLensHigh(); 316 | 317 | // Write 11 bytes 318 | for(uint8 i = 5; i < 16; i++){ 319 | writeByte(data[i]); 320 | } 321 | 322 | // Wait for the lens to go low; this signals the handoff, just like other checksums 323 | waitLensLow(); 324 | 325 | // Read one byte 326 | pinMode(DATA, INPUT); 327 | digitalWrite(BODY_ACK, LOW); 328 | waitLensHigh(); 329 | digitalWrite(BODY_ACK, HIGH); 330 | data[16] = readByte(); 331 | 332 | delayMicroseconds(100); // Wait a little while (to match the camera, not sure if necessary) 333 | digitalWrite(BODY_ACK, LOW); // Clean up after ourselves 334 | } 335 | 336 | inline void pulseShutter(void) 337 | { 338 | digitalWrite(SHUTTER, HIGH); 339 | delayMicroseconds(500); 340 | digitalWrite(SHUTTER, LOW); 341 | } 342 | 343 | int main() 344 | { 345 | init(); // Arduino library initialization 346 | setup(); // Pin setup and other init 347 | powerup(); 348 | 349 | uint16 packetNum = 0; // Count of how many packets we've sent 350 | uint8 standbyResponse[STANDBY_RESPONSE_BYTES]; // Last standby response we've gotten 351 | 352 | while(1){ 353 | if(packetNum == 1){ 354 | // Unknown (but presumably important) setup command 355 | delay(9); 356 | pulseShutter(); 357 | delayMicroseconds(1500); 358 | standbyPacket(standbyResponse); 359 | 360 | // Now send an extended packet with an aperture command 361 | uint8 one[] = {0x60, 0x80, 0x06, 0xfe, 0x00, 362 | 0x0a, 0x00, 363 | 0x01, 0x00, 0x00, 0x00, 0x00, 364 | 0x00, 0x00, 0x00, 0x00, 0x00}; 365 | extendedPacket(one); 366 | 367 | delay(4); 368 | digitalWrite(FOCUS, !digitalRead(FOCUS)); // Flip the focus pin 369 | } 370 | else if(packetNum == 3){ 371 | // Aperture command 372 | delay(9); 373 | pulseShutter(); 374 | delayMicroseconds(1500); 375 | standbyPacket(standbyResponse); 376 | 377 | // Now send an extended packet with an aperture command 378 | uint8 one[] = {0x60, 0x80, 0xfe, 0x02, 0x00, 379 | 0x0a, 0x00, 380 | 0x01, standbyResponse[8] + 1, standbyResponse[9], 0x00, 0x00, 381 | 0x00, 0x00, 0x00, 0x00, 0x00}; 382 | extendedPacket(one); 383 | 384 | delay(4); 385 | digitalWrite(FOCUS, !digitalRead(FOCUS)); // Flip the focus pin 386 | } 387 | else if(packetNum % 60 == 3){ 388 | // Aperture command 389 | delay(9); 390 | pulseShutter(); 391 | delayMicroseconds(1500); 392 | standbyPacket(standbyResponse); 393 | 394 | // Now send an extended packet with a command 395 | uint8 one[] = {0x60, 0x80, 0x03, 0xfe, 0x00, 396 | 0x0a, 0x00, 397 | 0x01, 0x00, 0x00, 0x00, 0x00, 398 | 0xd7, 0xff, 0x01, 0x00, 0x00}; // All the way in? 399 | extendedPacket(one); 400 | 401 | delay(4); 402 | digitalWrite(FOCUS, !digitalRead(FOCUS)); // Flip the focus pin 403 | } 404 | else if(packetNum % 60 == 33){ 405 | // Aperture command 406 | delay(9); 407 | pulseShutter(); 408 | delayMicroseconds(1500); 409 | standbyPacket(standbyResponse); 410 | 411 | // Now send an extended packet with an aperture command 412 | uint8 one[] = {0x60, 0x80, 0x03, 0xfe, 0x00, 413 | 0x0a, 0x00, 414 | 0x01, 0x00, 0x00, 0x00, 0x00, 415 | 0x4e, 0x02, 0x00, 0x00, 0x00}; // A bit out 416 | extendedPacket(one); 417 | 418 | delay(4); 419 | digitalWrite(FOCUS, !digitalRead(FOCUS)); // Flip the focus pin 420 | } 421 | else{ 422 | // Just a standby packet 423 | delay(9); 424 | pulseShutter(); 425 | delayMicroseconds(1500); 426 | standbyPacket(standbyResponse); 427 | 428 | delay(4); 429 | digitalWrite(FOCUS, !digitalRead(FOCUS)); // Flip the focus pin 430 | } 431 | packetNum++; 432 | } 433 | 434 | 435 | } 436 | --------------------------------------------------------------------------------