2013-01-10

Retrofitting Polaroid flashgun #268 with electronic flash

The original Polaroid flashgun #268 was designed for disposable flashbulbs. These flashbulbs could only be used once and were not produced for a long time. The only option to buy them would be ebay, garage sales, etc.
Sure, it's possible to use a modern electronic flash with Polaroid, but it's not fun, I wanted to preserve the authentic look. So I got myself the original flashgun (luckily this thing doesn't have any collectibles value, I got mine for $5 on the ebay) and retrofitted it with modern electronic flash.

Disclaimer: Danger, danger, high voltage! This device produces a potentially dangerous high voltage even after the battery is disconnected. If you managed to kill/injure/scare yourself, your GF/BF, buddies, pets, parents, etc. I am not responsible for it in any ways.

My Polaroid Land 440 with original flash


Original flash itself


Flash exploded

Electronic flash from the disposable camera. I got this, although anything similar should work.



I kept the same schematic as it was. I definitely drew it somewhere, but can't find it. Fortunately this PCB is so simple, you shouldn't have any problem making the schematic of it. Connectors on the board are also obvious:

  • battery holder - AA battery
  • metal tab switch - power on/off
  • black and red wires - trigger (sync contact)

The PCB was too big to fit into the case, so I split it into two smaller boards:

  • Cut-off a piece of the original PCB (around the charge transformer/transistor) to make a main charging circuit. The diode is not on this board, it is inside the heat shrink tube and soldered inline with the yellow wire (which is connected to the "-" of the main capacitor). 
  • Made a tiny trigger PCB (it has only HV transformer, capacitor and resistor) on the tiny piece of the perfboard. Neon lamp is wired outside of the board with current limiting resistor inline with the purple wire (the resistor is inside the heat shrink tube)

Rest of it is just wires to make an original schematic.




 Hot-glue everything together!


It runs of the single AA battery

Done


Video


Poorly scanned pictures taken with this flash




2012-09-24

Revealing hidden awesomeness of the TI MSP430 LaunchPad

TI (Texas Instruments) is awesome, I've always known it. What I like the most is their extremely low-cost ($4.30, who beats that?) Launchpad development kit that includes 2 "value line" (pronounced "super-cheap") micro-controllers, USB programmer and development software. That is everything you need to dive into the wonderful world of the super-lower-power microcontrollers.


Picking the test project
There are so many options for the first project: flashing LED, doomsday device, iSomething…
Hm, iSomething sounds like a cool idea. How about making a poor-guy MP3 player? Maybe downgraded to the extreme: one song, poor audio quality, no control buttons?
To make digital audio player we need two major components: storage memory for digital audio and Digital-to-Analog  Converter (DAC). Expectedly, such a simple microcontroller does not have a built-in DAC, so sounds like I would need a separate chip. But wait,

Who needs a DAC for lousy quality audio?
There is an easy alternative to DAC – Pulse Width Modulation (PWM). The idea is to generate audio signal with variable-width digital pulses, with high enough pulse frequency it should produce acceptable quality audio. Sure enough TI has an application note to demonstrate exactly that (PWM for audio application). Since I decided not to worry about audio quality, I picked 8 bit for audio resolution (as a side note - it is supposed to be roughly equal to AM radio quality). 8 bit resolution gives me 256 possible PWM widths (for example, value 10 means that output stays on for 10 cycles and after that turns off for 255-10=245 cycles).
Assuming that my TI chip runs at the max speed (16 MHz) my complete PWM cycle would be: 16,000,000Hz/256=62,500 Hz. Wow, at such high PWM frequency I should be able to generate sound with frequencies up to 62,500Hz/2=31,250 Hz (this calculation is based on Whittaker–Nyquist–Kotelnikov–Shannon sampling theorem). But it also means that I have to store 31,250 bytes of data for 1 second of music. Where am I going to store my music?

External storage
MSP430G2231 only has 2KB of memory. Because I need 31,250 bytes to store 1 second of music, I could store the whole 0.06 seconds using internal storage. This is definitely not enough. Well, it just means that I need an external storage. How about  SD/MMC Card? It is a perfect external storage for microcontrollers because it is inexpensive and supports very microcontroller friendly SPI protocol. The Launchpad came with 2 chips: MSP430G2211 and MSP430G2231 the latest has built-in universal serial interface that supports SPI protocol, perfect! And of course after checking TI website, I found this application note to interface between MSP430 and SD Card. Now I need to decide how to store the music.

Audio format battle: mp3 vs au
It would be really cool to play mp3 files on the Launchpad, but it's not going to work. For example, the smallest Helix mp3 decoder needs ~20K of program memory, and my microcontroller has only 2K. Of course I could add an external mp3 decoder - but that's not fun.
Since mp3 is not going to work, I could just write audio as a stream of samples (bytes) and add simple header to tell how many samples in my file, sample rate, etc. But it would be nice to use a standard audio file format, so I choose arguably the simplest audio file format ever created: au format. Even it is a quite old format, but still is supported by many applications including my favorite (open source) audio editor – audacity.

Getting audio file to the SD card
To store file to a SD card is also tricky. For multiple reasons I decided not to use a file system on the SD card, so I have to write .au file to the card as a raw data. This could be done by HDD imaging tools, I had good experience with DiskImage, although other disk imaging software (such as dd) should work.

Hardware
There are only two external components to the Launchpad used: SD card and earbuds headphone. I connected SD card power to one of the Launchpad pins, so I can reset the card by toggling its power. Earbuds headphone connected to the Launchpad PWM output pin through a current limiting resistor. "But where is your low-pass filter?" curious reader will ask. Well, yes, I should be using a low-pass filter to smooth-out PWM pulses. But headphones work well enough as a low-pass filter due to their mechanical nature. So, cancel the filter and connect everything together!

SD card access time issue
After fixing a few software bugs I finally heard something in the headphones. It was sort-of a music, but with some strange clicking noise. Such a disappointment! I though I was done with it.
It turned out that data on the SD card stored in 512 byte blocks and sometimes switching these blocks takes some time, so every so often I was missing a few samples and it caused those clicks. I added a small (16 samples) FIFO buffer between SD card and PWM. Buffer made its magic and I was enjoying AM quality music for a whole 15 minutes or so.

Conclusion
It's totally possible to play an acceptable quality audio using the most basic microcontroller. Sample rate could be pretty high (~31kHz in my case) and allows to achieve a much better audio quality, although PWM resolution (8 bit) is a limiting factor.
One of the options to drastically improve audio quality would be to use two independent 8 bit PWMs and summing up their signals. This would increase audio resolution to 16 bits which should sound (almost) like a CD quality. Although, MSP430G2231 has only one PWM channel, so it's not an option here.

Video
Here is a video of the Launchpad playing (kind of) music, enjoy.



Source Code
Grab it here.

2012-03-19

Read Command Line Parameters from VBA

Recently, I needed to read a command line parameter within a VBA code (it's for an Iconics SCADA application, but I developed it with Excel VBA which is essentially the same). It doesn't sound like a big deal but there were a few not-so-obvious tricks that I thought were worth sharing.
I started with the simplest solution using a "GetCommandLineA" Windows API function from kernel32.dll. It was supposed to return a pointer to the command line string, so I assumed that its return type would be string (sounds logical to me).
' The return type of the GetCommandLineA is long
' But it is supposed to be a pointer to the string. 
' Assumming that all VBA strings are passed by pointers
' Just declare it's return type to be a string
Declare Function GetCommandLineA Lib "Kernel32" () As String
 
Sub ReadCmdLine()

   Dim strCmdLine As String ' Command line string   
   ' Read command line parameters into the string
   strCmdLine = GetCommandLineA

End Sub
Surprise - it caused exception and crashed the application. Hm, apparently VBA handles a pointer to the string differently than GetCommandLineA. Not wanting to spend time figuring out why, I decided to copy the string to VBA string using another kernel32.dll function "lstrcpynA".
' Declare the return type to be a pointer (long)
Declare Function GetCommandLineA Lib "Kernel32" () As Long
Declare Function lstrcpynA Lib "kernel32" ( _ 
   ByVal pDestination As String, ByVal pSource As Long, _
   ByVal iMaxLength As Integer) As Long
 
Sub ReadCmdLine()

   Dim pCmdLine as long     ' Pointer to the string
   Dim strCmdLine As String ' Command line string     

   pCmdLine = GetCommandLineA
   ' Copy from the pointer to VBA-Style string 
   ' 300 characters for command line seems to be enough
   lstrcpynA strCmdLine , pCmdLine, 300    

End Sub

This worked better by no longer crashing the application, but the strCmdLine was always empty. After short Google search I found this Microsoft article. Apparently lstrcpynA function (as other DLL functions returning strings) can't change the size of the VBA-style string. In order to reserve the space for that return data, we need to fill the string with a bunch of zeros (vbNullChar).
Declare Function GetCommandLineA Lib "Kernel32" () As Long
Declare Function lstrcpynA Lib "kernel32" ( _
   ByVal pDestination As String, ByVal pSource As Long, _
   ByVal iMaxLength As Integer) As Long
 
Sub ReadCmdLine()

   Dim pCmdLine as long     ' Pointer to the string
   Dim strCmdLine As String ' Command line string   

   ' Get the pointer to the command line string
   pCmdLine = GetCommandLineA

   ' Fill the string with zeros
   ' 300 characters for command line seems to be enough
   strCmdLine = String$(300, vbNullChar)

   ' Copy from the pointer to VBA-style string
   lstrcpynA strCmdLine , pCmdLine, Len(strCmdLine )

   ' At this point we got the string
   ' But rest of it filled with 0 characters.
   strCmdLine = Left(strCmdLine , InStr(1, strCmdLine , _
      vbNullChar) - 1)
       
End Sub

This code finally worked as expected, returning command line arguments.
Hopefully, this article is useful in saving someone 15 minutes of frustration.