Kodak MegaPlus 4.2i Control Unit

Recently, a friend of mine who's also interested in vintage digital cameras bought a rather unique looking camera off of eBay: a Kodak MegaPlus 4.2i. The MegaPlus series of cameras were originally produced by Kodak starting in 1986 as the first >1 megapixel digital cameras available on the market, and due to their extremely high price tag (as much as $40k!) they were only intended for scientific and industrial use. These cameras have zero controls, indicators, displays, or storage of their own, so they must be connected to a computer that's equipped with a compatible frame grabber card in order to be used. (We originally thought that the camera would just connect over regular SCSI due to the fact that it has a 68-pin D-sub connector on the back, but it turns out that it uses entirely custom signalling that has nothing to do with SCSI at all.) Finding a compatible frame grabber card nowadays sounded like a horribly expensive nightmare - plus it would mean that the camera couldn't be used portably at all - so instead I decided to attempt to implement the MegaPlus's communication interface myself and build my own frame grabber gadget instead.

Camera specifications

This MegaPlus features a 2029x2044px, 18.5×18.5mm CCD sensor with 10 bits of dynamic range. It's compatible with C-mount lenses, although an F-mount version of the camera was also available. The sensor doesn't have a Bayer filter or IR cut filter over it, so it's a natively monochrome and full-spectrum camera which is super cool! After doing some testing, its ISO range seems to be equivalent to 30-500 which is also super cool as I've never seen a digital camera with that low of a minimum ISO before.

The finished product

Here's what my finished, battery powered, portable-ized MegaPlus looks like. I'm using an F-mount to C-mount adapter so that the MegaPlus can use regular, cheap, commonplace Nikon lenses instead of expensive and hard-to-find C-mount lenses. I also created labels for the Control Unit's buttons and enclosure by printing on some transparent Avery labels and cutting them to size.

complete1.jpeg

complete2.jpeg

complete3.jpeg

Photo examples & shooting experience

I've taken the MegaPlus out to shoot with a couple of times so far and it's a very interesting camera to use. Here's some of the photos that I've taken with it:

The MegaPlus's photo quality looks exceptionally good - I can definitely see why it was so expensive when it was new! It's a very high-contrast camera and is very easy to overexpose as is evident from my photos, so it requires careful exposure control (which I need more practice in). Using the MegaPlus is as manual of an experience as it gets - you need to manually set your aperture, shutter speed, ISO, focal length, and focus all without being able to see through any kind of live viewfinder or getting any kind of real-time feedback at all. This means that you need to go through an iterative guess-and-check process to take a good photo with this camera. After adjusting any settings (or even slightly moving the camera to change composition), you need to take a test shot to see how your photo turned out, further adjust any settings or framing that you got wrong, take another test shot, and rinse and repeat until you've built up a good photo.

While I wouldn't want this to be my only camera, the fully manual, methodical nature of it is an enjoyable change of pace from “regular” digital cameras. It forces me to slow down and carefully plan out each shot, as every aspect of the exposure and composition need to be adjusted meticulously. I also never really “got” black & white photography before, but now that I have a natively black & white camera, I understand the appeal of it a lot more. I still generally prefer shooting in color personally, but black & white will be fun to do on occasion.

Building the Control Unit

As mentioned earlier, I really didn't want to try to find a frame grabber card for the MegaPlus - it would be expensive, difficult (if not impossible) to use if the software wasn't archived anywhere, and would limit the use of the camera to only the inside of my house. What fun is a camera that you can't actually use anywhere? I know how the camera's communication protocols work (see below), so theoretically I should just be able to program a microcontroller to interface with it.

The high speed of the MegaPlus's parallel image transfer (10MHz * 10bpp = 100Mbps) means that I'll need a pretty fast microcontroller to fully capture the image, so I chose the Teensy 4.1 for this project - the fastest Arduino-compatible microcontroller currently available that I know of. The Teensy 4.1 also features expandable RAM (a necessity for this project as each image produced by the camera is 4MB and the Teensy “only” has 1MB of onboard RAM) and a built-in microSD card slot (convenient for storing captured photos), so it's the perfect choice for this application.

Figuring out image capture

starting_spaghetti.jpg Of course I didn't have a spare 68-pin D-sub connector on hand when I started out on this project, so I just shoved 28AWG wires straight into the digital interface connector on the back of the camera and it actually worked. I also didn't have any RS232 transceiver chips on hand either, so in order to control the MegaPlus, I just had to connect it to my Mac with a USB-to-RS232 adapter and manually type commands into the terminal.

On the Teensy, I would need to connect the camera's parallel data lines to contiguous GPIO port pins in order to efficiently capture the data in parallel, and GPIO6 is the most convenient one to use for this application. To make things easier, I'm only capturing the upper 8 bits of each pixel and disregarding the lower 2 bits. I'm throwing away a bit of potential dynamic range, but I would much rather work with nicely byte-aligned 8-bit words instead of trying to wrestle weird awful 10-bit words, so I'm totally fine with the trade-off. (Maybe someday if I can scrounge up enough spare motivation I'll try to capture all 10 bits, but don't count on it.)

To capture the parallel image data, I originally tried just executing an interrupt on every rising edge of PIX_DATA_STRB (the 10MHz pixel data clock), but even with the Teensy's ridiculously fast 600MHz CPU, I couldn't trim down my ISR enough to capture every clock pulse - I was missing every other pixel. After giving up on that, I then tried interrupting on every rising edge of LINE_ENA (the start of each line) and just counting cycles to capture each pixel in the line in a for-loop (at a 10MHz pixel clock and 600MHz CPU clock, that's 60 cycles per pixel). This was actually working for the most part, but the captured image was full of weird artifacts and the Teensy was somehow capturing more lines than the camera was sending, so I eventually gave up on that idea too.

Finally, I came up with a successful technique: interrupt on the rising edge of FRME_ENA (the start of the image transmission) and just execute a massive ISR that blocks for the entire image transfer (not very good practice but it works). In the ISR, a tight for-loop captures one line's worth of pixels (timed by counting cycles just like in my previous attempt), then the routine waits for the next line to start by polling the state of LINE_ENA and watching for a rising edge, then the for-loop runs again to capture the next line's pixels. After 2044 lines are captured this way, the ISR exits and the image capture is complete. When doing this method, the Teensy does count a total of 2048 lines per image, which is exactly the correct number of lines the camera should be sending. That makes the weird behavior of my failed LINE_ENA-based interrupt technique even more baffling.

Hardware design

hardware.jpg The current, mostly-complete version of my MegaPlus Control Unit uses the following hardware:

  • 8MB PSRAM chip installed directly onto the Teensy - necessary for buffering the 4MB images produced by the MegaPlus (more info about Teensy memory expansion here)
  • ICL3232 serial transceiver chip to allow the Teensy to communicate with the MegaPlus via RS232
  • Murata 5V regulator so that the Control Unit and MegaPlus can share a single 24VDC power supply (this little regulator is super neat - it's a drop-in replacement for the ubiquitous 7805 but is crazy efficient and produces basically no heat because it's a switching regulator)
  • Generic 128x160px SPI LCD from eBay for the viewfinder display
  • 68-pin SCSI ribbon cable (also from eBay) that I sliced up to connect to the MegaPlus's digital interface connector

To power everything, I added a barrel jack to the Control Unit that accepts a 12-28VDC power supply (the operating range of the MegaPlus). This voltage is directly passed through the Control Unit to power the MegaPlus, and is also regulated down to 5V internally to power the electronics in the Control Unit.

All of the electronics are installed on a hand-wired protoboard “PCB”. I had considered just designing an actual custom PCB like I did for my lyte:byte project, but I'll only be making one of these units and it's been a long time since I've done a hand-wired protoboard so I could use the practice. Like I always do with my protoboards, I used 30AWG wire-wrap wire to route all the connections on the underside of the board, sorta like PCB traces.

The enclosure is a simple 3D-printed design made out of Inland white marble filament. I love using marble filament for retro tech related projects - it's way more interesting than just using beige but still has a convincing retro tech look (although 3D-printed beige enclosures can still look pretty good). To attach the Control Unit to the MegaPlus, I just stuck it to the top of the camera with some velcro. It's actually surprisingly ergonomic to use like this - the LCD acts as a waist-level viewfinder so it's basically like holding and using a TLR or Brownie. (Hmm, both the Brownie and MegaPlus were made by Kodak and I basically just turned the MegaPlus into a digital Brownie…) Because the Control Unit is only attached with velcro, it can be removed and held separately for easier use when the camera is mounted on a tripod.

UI design

The UI of the Control Unit operates somewhat similarly to the UI on my Blossom project, but many adjustments had to be made to account for the unusual operation of the MegaPlus. The viewfinder display shows the last image captured, the current exposure parameters (shutter speed and ISO), a simple light meter, histogram, and a status message. My light meter is honestly not that great and operates just by calculating the average brightness of the entire image, then calculating the number of stops that the average brightness is away is from middle gray (RGB value of 119) assuming a gamma of 2.2. This camera's brightness response doesn't really seem to follow a simple constant gamma so I'm not too sure how to improve the light meter further, but it definitely needs some work. The histogram, as usual, is a much better tool for accurately gauging exposure.

There are six buttons surrounding the display: Increment, Decrement, Return, Shutter, Save, and Magnify. Increment and Decrement adjust the value of the currently selected parameter, Return switches what parameter is being adjusted, Shutter commands the MegaPlus to take a photo, Save saves the last photo captured to the SD card, and Magnify zooms in on the center of the image to provide a focus magnifier.

The MegaPlus supports specifying arbitrary shutter speeds at 1 millisecond resolution but that's not photographically useful when actually trying to shoot with it, so instead I provide a list of shutter speeds between 1/1000 and 30s at 1/3 stop increments to choose from. Likewise, the ISO options I provide are between 30 and 500 at 1/3 stop increments (which maps to 0-24dB at 2dB increments). During normal operation, pressing the Increment and Decrement buttons will adjust the value of one of these parameters, and pressing the Return button will switch what parameter is currently being adjusted.

Having Shutter and Save be two separate buttons sounds like a pretty bizarre UI choice at first, but as I mentioned earlier, the MegaPlus doesn't provide any kind of viewfinder or live-view functionality at all so you have no idea what you're going to get when you fire the shutter. Instead, you have to guess-and-check your way to getting a good photo: set your exposure parameters, focal length, and focus to something that seems decent, then take a photo, see what you got wrong, tweak your parameters to compensate, and rinse and repeat until you've binary-space-partitioned your way to a good picture. You'll probably take over a dozen exposures during this process and you wouldn't want to save every single one of them to the SD card because most of them will be awful, so that's why the save button is separate - you only press it when you're finished with the process and are happy with the photo you've created.

Likewise, the dedicated Magnify button is there to help you check if you've actually taken a focused picture or not. The MegaPlus has no autofocus or focus-checking abilities at all, so it's up to you to manually achieve focus. After taking a photo, you can activate the focus magnifier by holding down the Magnify button - this will cause the viewfinder display to zoom in on the center of the image to give you a better look at fine details in the shot so you can judge focus. The zoom level can be adjusted (from 2x to 10x) by pressing the Increment and Decrement buttons while the focus magnifier is active.

Running on battery power

battery.jpeg In order to actually use the MegaPlus as a camera, it needs to be able to run on battery power - plugging it into an outlet during a photowalk just isn't gonna happen. Fortunately, the MegaPlus's wide input voltage range of 12-28V encompasses the voltage range of common 4S lipo drone batteries, so I bought one of those batteries and an XT60 to barrel jack adapter, then 3D printed a Battery Bucket™ that attaches to the back of the camera with double-sided tape. It actually works and seems to last about an hour and a half per charge, which isn't as bad as I was expecting!

I added a simple battery meter to the UI that shows a rough charge level based on the estimated voltage per cell: 4.2v/cell is completely full and 3.2v/cell is completely dead. I'm using a resistor divider to divide the incoming voltage by 11 so that the Teensy's ADC (which can only tolerate up to 3.3v) can read it safely.

How the MegaPlus interface works

It turns out that implementing the MegaPlus's interface isn't very difficult at all - I got extremely lucky and was able to find a manual for the MegaPlus 4.2i online that described the pinout and communication protocol of the camera in great detail, so all I had to do was implement what the manual described.

Digital interface connector

This MegaPlus uses a single 68-pin D-sub “digital interface” connector for all communication, control, and image data transfer. Communication and control occurs over standard RS232 (9600 baud 8N1) and image data is transferred using a 10-bit 10MHz parallel interface, one pixel at a time. I'm not sure why Kodak used such a large connector as only about half of the connections on it are even used, and only half of those used connections are actually unique because each signal is presented as a differential pair. If you don't care about using differential pairs (I sure didn't), then there's only a max of 16 connections that need to be used, all along the top row of the connector.

connector.jpg

Pin Function
1, 12, 34, 35, 46, 68 Signal ground
2 Pixel data bit 9 (MSB)
3 Pixel data bit 8
4 Pixel data bit 7
5 Pixel data bit 6
6 Pixel data bit 5
7 Pixel data bit 4
8 Pixel data bit 3
9 Pixel data bit 2
10 Pixel data bit 1
11 Pixel data bit 0 (LSB)
22 SER_CNTRL_OUT (RS232 TX)
23 SER_CNTRL_IN (RS232 RX)
25 FRME_ENA (high when an image is being transferred)
26 LINE_ENA (high when a line of pixels is being transferred, low during HBLANK)
29 PIX_DATA_STRB (10MHz data clock - new pixel data is available on pins 2-11 at rising edge)

Controlling the camera via RS232

The MegaPlus is entirely controlled via standard RS232 serial (on pins 22 and 23) at 9600 baud and 8N1 format. Conveniently, all of the communication uses standard human-readable ASCII text. Each command sent to the MegaPlus consists of a 3-letter instruction, followed by a space, an argument value (either a base-10 integer or character string), then terminated with a carriage return and line feed (CR-LF). For example, to set the shutter speed (“EXE” instruction) to 50ms, send “EXE 50” followed by CR-LF.

After the camera executes a valid instruction, it will acknowledge by replying with a blank line (CR-LF only). If the camera did not understand your instruction, it will reply with “E-SYNTAX” followed by CR-LF, and if the instruction was correct but the argument you specified was out of range, it will reply with “E-ARG RANGE” followed by CR-LF.

To query the current value of a parameter, send a 3-letter instruction immediately followed by a question mark (“?”) then a carriage return and line feed (CR-LF). The camera will reply with the current value of the parameter you specified. For example, to query the sensor gain (“GAE” instruction), send “GAE?” followed by CR-LF, and the camera will reply with the current sensor gain value followed by CR-LF.

Instruction set

To denote argument data types, this table uses “x” to refer to 1-letter strings, “xx” to refer to 2-letter strings, and “#” to refer to variable-length integer values.

Instruction Description
MDE xx Sets the drive mode.
MDE TR = Trigger (take photos when TRE command is sent or pin 30 (EXPOSE) is high)
MDE CS = Continuous (take photos constantly while powered on)
MDE CD = Controlled (exposure will start when pin 30 (EXPOSE) goes high then end when it goes low, bypassing internal shutter speed setting)
MDE PI = Parallel interface (drive mode is controlled by pins 31-33 (MC0-MC2))
SHE xx Manually controls the shutter and forces it open or closed.
SHE ON = Shutter enabled (regular operation)
SHE FO = Force shutter open
SHE FC = Force shutter closed
EXE # Sets the shutter speed in milliseconds. Range is 1 to 100000 (1ms to 100 seconds).
TRE # Starts or stops taking photos (MDE must be set to TR). After a start instruction is sent, the camera will continuously take photos until a stop instruction is sent.
TRE 0 = Start taking photos
TRE 1 = Stop taking photos
TRM x Sets the polarity of the EXPOSE signal (pin 30) on the digital interface connector.
TRM P = Positive logic (a high level will start exposure and a low level will stop exposure)
TRM N = Nositive logic (a low level will start exposure and a high level will stop exposure)
TRM O = EXPOSE signal is disabled and only TRE command can be used to start/stop exposure
GAE # Sets the gain (ISO) of the sensor in dB. Range is 0 to 24, in 2 dB increments (only even numbers are accepted). A change of 6 dB doubles or halves the sensitivity of the sensor (changing it by 1 stop), so this command allows the gain to be set in 1/3 stop increments. From my testing, 0 dB is approximately 30 ISO and 24 dB is approximately 500 ISO.
BKE # Sets the black level (brightness) of the camera's image. Range is -2048 to 2047.
BKF Sets the black level of the camera's image to factory defaults. This command does not accept an argument.
STP x Sets the polarity of the strobe (flash) output.
STP P = Camera will output a rising edge to fire flash
STP N = Camera will output a falling edge to fire flash
DEF xx Enables defect correction, which accounts for variances in light sensitivity across different pixel columns on the sensor.
DEF ON = Enables defect correction
DEF OF = Disables defect correction
SAV Saves all of the camera's current settings to EEPROM so that their values will persist after power-off. This command does not accept an argument.
RST Loads all of the camera's settings from EEPROM, undoing any changes that have been made since the last SAV command. This command does not accept an argument.
STS? Queries the current status of every command/parameter all at once.
IDN? Queries the model number and firmware version of the camera.

Acquiring image data from the camera

imagelayout.jpg Whenever the MegaPlus takes a photo, it immediately dumps out the captured image data through the digital interface connector using a parallel data protocol at a rate of 10MHz (each pixel is 10 bits so that's 100Mbps!). Each pin on the connector seems to use approximately 3V logic levels (I measured 3.7V on mine).

The camera constantly produces a 10MHz clock signal on PIX_DATA_STRB (pin 29) whether it's currently transmitting an image or not. FRME_ENA (pin 25) will go high when the camera is actually transmitting image data. During the image transmission, LINE_ENA (pin 26) will go high when a line of pixels is being transmitted, then go low during a sort of “HBLANK” period to mark the end of each line. Each image consists of 2048 total lines (2044 valid lines at the start of the image then 4 invalid lines at the end) and each line consists of 2368 total pixels (2029 valid pixels when LINE_ENA is high and 339 invalid pixels when LINE_ENA is low), for a valid image size of 2029×2044 pixels.

Pixels are transmitted one at at time - left-to-right then top-to-bottom. The 10-bit brightness value for the currently transmitted pixel should be read in parallel from pins 2-11 at the rising edge of PIX_DATA_STRB. (Remember, pixel data is only valid when both FRME_ENA and LINE_ENA are high).