Is a cute lo-fi portable video recorder which uses the once popular Nintendo GameBoy Camera cartridge.
This was initially a 2-week rush project for the RGC 2015 (French retrogaming meeting).
It involved designing a custom PCB and a 3D-printable half case, writing the firmware, and assembling by hand.
It was finished 3 days late because of various issues, mainly with the SD card, which I'll talk about further down.
Since I knew that the custom parts would take about 9 days to be manufactured and delivered, I gave myself 2 days for the design work and 2 more for assembly and testing. I wrote most of the firmware "blindfolded" while waiting for the parts.
All the design files are available on Github: https://github.com/furrtek/GBCamcorder
Beware, the PCB layout contains errors and wasn't revised yet ! See schematic.
Here are the features (for now):
- Unsteady framerate ~14fps 128*112px video (wanted to have steady 16fps)
- 8192Hz audio (to match the samplerate of many GameBoy games that used samples)
- Recording on FAT32 µSD(HC)
- 240*320px LCD for the viewfinder and UI
- Auto-exposure with out-of-range alerts
- USB rechargeable LiPo battery (lasts for about 2 hours)
What I'd like to add:
- Playback of recorded files (with sound)
- Various picture options
- File browse, name, delete...
- USB mass storage
- Webcam mode ?
The 1998 GameBoy Camera was an official accessory for the GameBoy which could shoot and save up to 40, 128*112px pictures in 4 shades of grey.
Numerous projects use the GameBoy Camera's CMOS sensor, but according to Google none use the complete cartridge.
The main idea here is to preserve and show the cartridge as much as possible and interface to it directly, taking the GameBoy's place.
Decisions had to be taken quick since I didn't knew how much time would take PCB routing.
Knowing Atmel's 8-bit AVR MCUs since years, it was obvious that they wouldn't be powerful enough to handle all the tasks.
I chose NXP's LPC1343 ARM Cortex-M3 MCU for it's speed (72MHz max), price ($3), availability (Farnell), solderability (QFP), RAM size (8kB), and ease of development (free tools, and above all: USB firmware upload).
The GameBoy cartridge connector was purchased off eBay as a DS GBA slot replacement part, I just had to file the edges down to make original GB carts fit.
All the other components came from Farnell.
The 3D-printed polyamide case was ordered from i-Materialise (they're in Belgium). I got it in purple because my GameBoy Camera was green, so together it looked like EVA-01. I like EVA-01 :)
The PCB is slided in and maintained in place by the upper edge, and with 2 M3 screws on the bottom.
The battery is sandwitched between the PCB and the LCD board, which makes the overall quick thick but still pocket sized.
The schematic is simply based on the LPC1343's reference design (mainly for the USB part).
The 5V step-up converter for the power supply is a MCP1640, it has a bypass function to let VUSB run through.
The 3.3V regulator is a 1117-3.3, fed by the 5V rail.
The GameBoy cartridge address bus is spread from 8 GPIO lines by two HC574 octal latches.
The LiPo battery charger is a MCP73831.
The layout was done overnight, the footprint checking was done with scrap parts.
The electronics design was done in Labcenter's Proteus suite (will maybe move to Eagle).
The case was done in Solidworks. The firmware was written in LPCXpresso.
The board was ordered from the purple and gold people. It only had 3 errors. I was almost proud !
I admit I didn't chose the most open-source tools there are.
Still because of the time contraint, I decided to stay with the tools I was already familiar with.
For now, the firmware's architecture is pretty straightforward: A bunch of initializations, and a main viewfinder loop which can be interrupted by a timer when recording.
The most difficult part was to squeeze all the required steps for recording to get the highest possible framerate.
The viewfinder loop in idle can be quite smooth, it goes up to 25fps under bright light.
But as soon as recording is started, the SD card writes practically cuts the rate in half. This is due to a design flaw which I fell into because of the lack of experience: There wasn't enough RAM to buffer more SD card writes.
The main steps are as follows:
- The picture parameters are sent to the GameBoy Camera.
- A capture request is fired.
- While the capture is done by the cartridge itself (there's a custom mixed-signal chip in it !):
- The previous frame's brightness is computed and the exposure value adjusted.
- The frame is saved along with a varying number of audio frames to the SD card.
- The LCD is updated with the preview.
- The code then sits in a loop, waiting for the capture to end (it sure doesn't wait long !).
- The cartridge's buffer RAM is read and the cycle repeats.
This process is regularly interrupted by the recording timer which stores audio samples from the ADC in a ring buffer and also gives the video tick.
The UI font was ripped from Pokemon Yellow ;)
The file format
For now (V1), audio and video are recorded raw in the same file and need to be converted to a suitable video format on a computer with a special tool. Directly recording uncompressed frames to AVI can surely be done.
The file starts with 4 bytes: "GBCC".
Vx (0x56 xx) indicates the start of image data, and how many times the previous image has to be replicated (due to the variable framerate). One image is 3584 bytes, in the GameBoy's native format.
Ax (0x41 xx) indicates the start of one or multiple (xx) audio frames. Each are 512 unsigned bytes which need to be played back at 8192Hz.
Here's a typical file, yellow is images, green is audio chunks. You can clearly see the pretty unpredictable SD card lag:
Audio is given absolute priority because video stutter is more tolerable than skippy audio. The 6*512 bytes audio ring buffer can compensate for 375ms SD card write delay before eating itself up (which never happened even with my slowest SD card).
The failures !
- No 5V: Inverted a pair of pins on the MCP1640, nothing smoked. Fixed with cuts and wires.
- No USB power: MCP73831 bypass didn't work as expected. Fixed with cuts, wires and diodes.
- Not getting MCU to go in programming mode: Should have used a reset generator. Fixed by changing 2 resistor values.
- Couldn't talk to cartridge on battery power: Initially, the 3.3V LDO was directly connected to the battery. It gave 2.7V instead of 3.3V (1V dropout on 3.7V LiPo nominal voltage). This wasn't high enough for cartridge to register logic "1"s. Wired the LDO to be fed from the 5V step-up instead.
- Could create new file on the SD card, but not write to it: This sucked. The code wasn't waiting for the SD card to go back to idle after a sector write (see below).
- Loud audio noise matching SPI bursts: Bad capacitor placement.
- LCD not initializing: In fact, it was. It just didn't look like it because of a suboptimal refresh rate value.
- "Random" stutters during recording. Misread the SD documentation and found out that cards can have up to 250ms write times depending on some internal wear-levelling process. Needed to buffer multiple frames, but not enough RAM...
About the SD card issue:
Still because of time, I used ChaN's FATFS library to handle files. The SD interface code was slapped together from various sources and with the help of the SD specifications.
Initilisation worked, mounting worked, opening a file worked, reading a file worked, creating a new file worked, but writing to the file didn't.
The f_write function always returned FR_DISK_ERR, which really has no meaning.
A genuine 4GB Sandisk SD was freshly formatted to FAT32.
There's no write protection on µSDs, and FATFS was modified to not use a WP pin.
Power supply was good, no drops or heavy ripple on the 3.3V rail.
This was very annoying since the file creation worked (physical write to tha card's flash worked !)
Tracking down the cause of the reported FATFS error revealed that the card was answering correctly and wasn't reporting any errors. FATFS wasn't happy because the card only executed the first write command (to the FAT, the file creation) but not the following ones.
I spent hours running in circles just to realize that the SD card was actually reporting that the sector was buffered correctly, but nothing was indicating that it was being WRITTEN to flash.
Solution: After CMD24 and 0101b response (buffered ok), wait for 0x00 (card busy, it can be long), and then 0xFF (card idle) !
AntonioND, who wrote a very informative document about the GameBoy Camera.
GBCamcorder wouldn't have dithering without his work !
cLx, who helped me track the noise issue I was having with the microphone.
The RGC staff, for having unwillingly put pressure on me ;)