My kids' favourite tune is Twinkle Twinkle Little Star, and we usually sing it at bedtime. I recently picked up a cheap moon-shaped wall-mounted night light from Homebase for £5 (no link, sorry - it doesn't seem to be on their website. Also available from B&Q, but again, nothing on the website), and it's pretty useless in its standard form - the batteries last for no time at all, because it uses an incandescent light bulb. So I decided to put it to better use, and convert it to LED lighting, and to put in a music box version of Twinkle Twinkle at the same time.
The first challenge was being able to modify the music box code. It's in AVR assembler, which is a nuisance to find a decent compiler for on Mac OS X. I tried avr-as as bundled with Arduino, but it didn't understand a lot of the macro directives in the source. Eventually, I settled on a recommendation for gavrasm, and found some prebuilt binaries for v2.9 at XOR-Gate Engineering.
That assembled almost without modification, although gavrasm's internal chip definitions don't seem to include some that are present in the AVR header files, so I had to add those by hand. I uploaded the .hex file to an ATTiny, and found that it didn't work (even though the original .hex file by ELM was fine in the same circuit).
Comparing the two hex files, I noticed that there were differences. Hmm.
One set of differences were due to gavrasm's curious insistence on redefining what a relative immediate branch instruction should do - essentially, the relative offset calculation is different (see the readme for more details). After introducing some labels for relative jumps at what I reckoned we're the right offsets (diffs of the hex, and trial and error, were useful here) I eventually got down to 2 diffs that weren't related to branches.
Looking more closely, I realised that there was a bug in gavrasm when calculating the high byte of a negative immediate value. It was claiming that high(-255) was 0 rather than 255 (due to sign extension), and that disagreed with whatever ELM had assembled with. I worked around that by manual expansion of the 2 affected macros, and substitution with code that hard coded the correct values for the high byte.
Finally I had an identical .hex, which worked fine.
Next step was to change the tune. Using a score at makingmusicfun.net, I wrote a simple python script to generate melody.txt files in the format expected by the mel2asm.pl utility supplied by ELM. After a brief hiccup due to having forgotten my high school music reading lessons (I thought the note letters in the bass clef were the same as those in the treble clef - wrong! See here), I got a recognisable Twinkle Twinkle running on endless loop.
Breaking that endless loop was simple - look for the code that recognises the EndOfSong (EoS) marker in the data, and make it branch out to a new label instead of back to the start. The code at that new label just sends the MCU into deep sleep mode, requiring a falling edge on the /RESET pin to wake it up again and play the song once more.
I also modified the code to turn on an LED on pin PB3 (chosen to avoid interference with ICSP - I was making heavy use of the Frankentiny all the way through) of the MCU while the song is playing.
Mounting in the plastic moon was easy enough. It has a built-in 4xAA battery holder, arranged in series for 6V. I chose to rearrange the wiring for 2xAA + 2xAA in parallel, for 3V but longer battery life (my ATTiny85Vs can operate down to 1.8V). The bulb and holder just pulled out, and the old persistent-throw on/off switch was easy to pull out and replace with a momentary-action tactile switch, for operating the /RESET line.
I hot-glued a thin speaker where the bulb used to be, and surrounded it with 4 ultra bright white LEDs, with their legs splayed and embedded in some more hot glue. They were connected in parallel with a very low series resistor (47ohm) due to the 3V supply being close to their forward drop voltage, and the parallel arrangement splitting the current between the 4 of them.
The problem with most ultrabright LEDs is that they focus to a tight beam, which forms a bright spot on the cover of the light. There are various ways to diffuse them, but I chose to superglue a tiny square of tissue paper on top of each LED, which softened the light perfectly for my purposes.
Here's the schematic, simple as it is.
The code is available on GitHub.