Game Of the 2313 talking Geese (by makapuf)




The origin of this prototype is a game of the goose [goose] board game. It's a famous multiplayer board game in France, where the players advance with a dice along cases and try to reach the end, with special "bonus/malus" cases. My son designed one as a drawing, with special rules for each case and I wanted to do an electronic-enhanced version of it for him.

I didn't want it to be screen-based - it's not a video game-, so most of the interactions were to be audio-based, multiplayer. I decided to record my voice and say what each of the players has to do, say the dice result ... The toy should also be autonomous, so I decided against needing an external amplifier, and simple 1.2V batteries were needed, preferably two of them (we'll see that powering a speaker under those conditions isn't easy (for me at least)- without boosting it with an "expensive" extra IC).

The final result is a functioning board game running on batteries, but also a nice basis on which to make cheap talking toys : only about 4$ of parts [cost] have been used to build a complete amplified audio game with 1 minute Audio storage and many sentences. Compare this with the high-end solution of an arduino (15$?)+wave shield (22$) +SD card (around 5$?) (not the same sound quality of course, I find this shield great !). At the other extreme, ISD chips can have the same quality, can record, but they cost at least 10$ (that's the bare chip) and cannot embed any logic while a whole board game+sentence generating is integrated here.

Audio storage & playback

I decided to simplify the design and reduce pin count to use the MCU PWM output method instead of a dedicated DAC to play the audio.

The Audio, exported as 8bit unsigned at 8kHz with Audacity, was stored in a small Flash based IC (Atmel Dataflash). I used an AT45DB041d [dataflash] -type flash memory, because it's simple to interface with an MCU thanks to its SPI bus, and has some RAM buffers so RAM on the MCU is not needed.

The AT45DB 04 1d is 4Mbits large, so as I sampled my audio as 8kHz/8bits uncompressed (for now - [compression]), 64kbps allows 64s of audio, which was enough for my use.


The flash used is an At45DB041, since it has enough storage and is quite cheap ($1.3 on digikey for the 4Mb version). A small PCB adapter was needed since no DIP version exists.

The MCU chosen is an AVR atmel, programmed with ArduinoISP. Since we need 4 pins to talk to the flash (CS+CLK+DI+DO)+ Speaker output + a button for input + a led status, we needed 7 pins, so a 8-pins attiny was difficult (even at 6 pins if we multiplex the button+LED, there would be no reset .. ), so I decided to use an attiny2313 instead with pins to spare (or a 4313 if the code was too big). This one is still very cheap, fast enough and has an USI, which can serve if talked to politely to behave as an SPI for the dataflash.

The sound generation is done via the Fast PWM mode [pwmaudio].

The toy had to be self-contained, so a speaker driving was needed to be able to output loud sound. I used a simple transistor to drive the speaker, and it's much louder than a direct drive by attiny pins of course, even on 3V (LM386 amps are rated low voltage but need 4V at the very minimum and I wanted simple cells batteries, preferably two of them). I'm using the fact that the output is PWM, driving the (standard NPN) transistor in saturation. I could mayeb have used a MOSFET, but it's not a PA amplifier, so a bc548c by example has plenty enough of gain.

A RC lowpass filter was added before the transistor to improve the sound.


Everything was prototyped on a breadboard, then soldered on a prototyping board. Doing a proper PCB was too much of a hassle for my use, but could be done if anyone is interested - bonus point for small SMD components. (I should even do a Kickstarter ;)


The prototype wiring


The used protoboard style wiring (except for two wires added afterwards and present in the schema)


A possible PCB could be like : (zoom image to see it bigger)


(smd parts, 32x22mm=1.25x0.86 in., no ISP yet (!), untested )

Some awesome made by hand : attiny & dataflash programmers for arduino (yes, they're crap. I'm a cheapo)


Flash storage

To store the audio, I designed a small/simple filesystem on the AT45db to be able to store files on it and retrieve it simply based on the two 264 bytes SRAM buffers of the AT45DB.

The flash is divided in pages of 264 bytes.

The filesystem structure is the following :
  • 1-page header (could be 2 pages).

This will reside in a buffer and serve as a FAT.

4 byte header ("YEAH"), for tests and check whether flash is "formatted"

array of 4 byte records for all files :

page ID of file (high byte)
page ID of file (low byte)
length of last page (high byte)
length of last page (low byte)

Page ID of file is the page ID of the beginning of the file record. The last record used has a last page length used of 0 bytes.

  • the rest of the storage are variable length file records, with

    1 page filename (264 bytes max, padded with 0) N page file data

The FAT will always be stored in a SRAM buffer of 264 bytes (1 page), so there can be (264b -4b header)/4b record -1 EOF record = 64 files maximum.

So, to stream a file, the MCU needs to read the page ID from the FAT (always stored in the first SRAM buffer), and launch a continuous read method from the page_id.

I wrote a simple Arduino sketch to program the dataflash, based on the Arduino ISP program + dataflash library, issuing a few simple commands such as read page and write page, using an AVR STK500-like protocol.

I did not try to emulate exactly the STK500 protocol however, since I also wrote a simple python utility to :

Note that writing a file means rewriting the same page, but I don't plan to change the files so often. Also, there is no ways to delete a file short of formatting the flash.


Since we only have 128 bytes of RAM, storing the FAT in SRAM is out of question, but since I stored it in the SRAM buffers, it's always ready (Since the AT45DB has two of them, we could have stored 128 files).

The source of the firmware is available here, compiled with avr-gcc.

The program is divided in several parts :

To check the logic of the game and avoiding re flashing the attiny each time, I emulated a simple hardware in C, replacing saying a given phrase with printing it on stdout, compiling my emulator with gcc but a different "hardware library".

Then I programmed the 2313. I finally crammed the C code in 2044 bytes (4 whole bytes free on the 2313 ! luxury ! Those big C switch statements jump tables sure take some space so eliminating the comon cases with an if before helps).

Flashing the 2313 needed the at45DB to be removed since the ISP pins are the same than the USI DI/DO/CLK. It should be possible to desactivate the AT45 automatically via CS when the reset pin is driven low by the programmer, but removing the cable was simpler. eh.

To add randomness (ie entropy) to the PRNG included, I called rand() repetitively while waiting for the player to press the button (launch a dice, pass to the next player, ...). Thus we add randomness to the process which would have been repetitive.

Next steps

I'm satisfied with the current design, but I might reuse/improve it later :

[compression]Of course, adding mu-law encoding and/or DPCM coding would let me reduce the size of the given audio or increase the quality but that would enlarge the code size with mu-law tables and/or (a)dpcm algorithms, extra tests. So this is left as an exercise for the reader :)
[pwmaudio]See many tone generating libraries and examples (beware it's for arduino, we're on a smaller platform with 2k/128b instead of 32k/8k so some restrictions apply !) there : Also, a nice App note (which I discovered later) is presented here (pdf) :
[dataflash]datasheet here (pdf) :
[cost]dunno exactly, I reused some from my stock. Parts include : an Attiny MCU, dataflash, a button, a resistor and a led + a small speaker
Licence Creative Commons
comments powered by Disqus