Audioplayer based on Xmega AVR

History of Xmega SD Player

Alvidi ATxMega

A few months back I started on a small project for my girlfriend (Het Kunstwezen). She was preparing a detective game for a museum, to use for birthday parties. One of the items for this game would be the detective giving clues on how the game should proceed (give new clues, give assignments, etc.). How this should be done was unclear.

One of the ideas was to use an old phone and enter codes that would give the participants some info. I decided to try and realize this on an ATtiny2313, and I already made a nice library for a 2-row display when someone thought that it would be SO COOL if I could add one small feature: make the detective speak through the phone handset…

After making clear that this would prolong the development of the phone, but also seeing a nice challenge I started on this project.
One of the projects I really had in mind for a long time was making some sort of audio player based on a microcontroller board. I had heard about the ATxMega series from Atmel, and thought I might have a go at it.

Why Xmega?

Why use the AVR atxmega? I had several reasons to choose this microcontroller:

  • I wanted to learn myself programming a more complex microcontroller than standard AVRs, also to be ready for potential new projects
  • The ATxMega has timers, DACs, UARTS and an SPI bus plus enough clock speed to not worry about implementation in C
  • A very nice development board is available from Alvidi, containing a micro-SD slot, voltage regulator, crystals and programming headers for less than 50 Euros including postage
  • I had seen that the FatFs code from ELM-chan.org was used on xmega architecture.

Setup, targets

Hilversum IDK(?)

I started with the phone pictured on the right. I needed to read out the keyboard (row-column matrix), mimic ordinary phone behaviour (dialling tone, DTMF tones), and be reasonably idiot proof as kids would play with this thing.
This is the ‘architecture’ I chose:

  • Try to run as much as possible from interrupt routines
  • Audio files are read from SD card
  • To keep things simple, these files should be mono, 16kHz sampled, 16 bit files. No checks are performed.
  • Audio is output from one of the DACs
  • A second hand PC speaker setup is salvaged to provide power supply and an amplifier to drive the original handset speaker at a level suitable for a small group of participants to hear the assignments.
  • Use a UART to give debug info (I only have a AVRISPmkII, so I can’t place breakpoints)
  • I did not know what the story of the game would be. I thought it would be best if I provided a way to keep this open forever so gameplay can be changed. The participants get 9-digit codes from each finished assignment, if the code is correct they should hear a new message. Implementation is as follows:
    • When the phone is picked up, a dialing tone is played
    • When a number is pressed, the corresponding DTMF tone is played
    • After entering all digits a ‘check code’ button should be pressed (bottom right corner
    • The firmware checks the existence of a file called <code>.wav, so for example “123456789.wav” . When this file is found, it is played, when it is not found (wrong code) a ‘this number is disconnected’ file is played.
    • Whenever the handset is placed on the hook, all playback is cancelled.

    The game can always be changed by replacing files on the SD card; to change or add scenarios to the game just add audio files with new 9-digit codes (or remove them).

Implementation Details

FatFS / SD card

Thanks, thanks, thanks for writing this library! This has given me the opportunity to make this project in the first place! I just needed to write the low-level functions for SPI communication to make this work. At first I found that the connection after startup was very unreliable; after flashing it worked most of the times, but on ‘cold start’ the connection to the SD card failed often. I found out that I forgot to check on the default pin states (pullup, pulldown) for the IO lines, after checking with the scope I corrected this in the main function. Again: check FatFS. The only thing that I had to find out by reading the sources was that whatever size you give for ‘read’, a block of 512 bytes is always read. Reading smaller sized blocks gives no speed advantage.

One thing that is ‘throwing away performance’ in timing is that nothing runs from interrupt routines. In the SPI routines this means that ‘while bit is set’ wait routines are used to read / write data. Waiting for these bits to set means that other routines have a variable delay. This is why the circular buffer is so important.

Reading /playing wave files

The WAV file format is very easy; the firmware just skips the header, except for the ‘length’ field, which is used to determine how many bytes should be read from the SD card. The data is written to a circular buffer, and read from this buffer when playing back the audio. One routine is used to convert the 16-bit signed data to a 12-bit unsigned value for the DAC.

Audio output to amplifier

When building this setup I only had a rail-to-rail output opamp laying around, but I wanted to use the full analog output scale (0-3.3V) for output. To do this I am using an inverting amplifier circuit; the outpur from the DAC can be 0-3V3, but the input stays around 1.65V. I am using two DAC outputs to drive the output buffer that drives the amplifier. The DC offset for the positive input of the amplifier is generated by the second DAC channel to minimize the number of components needed outside the demo board:

Output amplifier

Amplifier should be RRO.
But: please read the possible improvements below!

Keyboard Matrix

The keyboard is a matrix of keys, I wrote a couple of functions to read the matrix. To be independent of hardware, the rows and columns can be on different microcontroller ports, and row / column position can be shifted in software. So: just connect the rows and columns, and correct your hardware mistakes in firmware! Debouncing is also taken care of in firmware.
In a later project I found out that on a older make of the T65 a different type of keyboard interface was used. When a key was pressed, one switch was closed for the row that was pressed, and another key was pressed for the column. In the newer phones the key that is pressed shorts a row and a column contact, the ‘standard’ matrix keyboard style. I decided to use the same function names, but decide based on the state of an otherwise unused IO pin which part of the function should be run: the ‘old phone’ or ‘new phone’ content. This way I can always flash the same file, and just short one pin to GND to get an other keyboard readout function.

Playlist!

Now, this feature is VERY useful! I’m using a five-level playlist where each item is ‘interruptible’ or not. If an item is interruptible, a new item being added to the list will be played instantly. If it is ‘uniterruptible’ the sound will play until finished or until the horn is placed on the hook. For example: the dialing tone is interruptible; when a key is pressed the dialing tone stops and the DTMF tone is played. The audio fragments of the ‘detective’ are ‘uninterruptible’. Key presses have no effect.
This feature also limits the amount of editing needed in WAVs. Audio effects / samples of picking up the phone and laying it down can be added to the playlist, and do not need to be added to WAV files.

LCD Display

Not used, but fully functional and included in the zip file with code. To be used with this display or similar.

Source Code and Pictures

The code posted is not what was used in the museum game, but what was used for an event where ‘infotelefoons’ were needed. The two T65 phones pictured below were built, and used the same code as basis. Differences:

  • - No DTMF tones
  • - Press a button, hear an attached audio fragment immediately (info1.wav – info0.wav), so no ‘missing connection’ tone needed.
  • - Keys next to zero key are not used.,/li>
  • + Added old keyboard matrix
  • + Improved initial pin state for SPI lines

Click here for the sources. The folder ‘SD’ is the default content of the SD card.

Caveats / improvements

What can be improved?

  • As I later found in the device Errata: up to 100LSB noise is added when using the DAC in sampled mode. This noise is clearly audible. One DAC is only used for creating a DC offset, this can also be done with an external resistor divider.
  • Use the DMA possibilities of the Xmega. In a later project I did for this device in my daytime job, I found that the DMA can be used very easily. Might have made it easier to copy data from the SD card to the ring buffer.

Demo Video

Quite boring video of a …phone…

It shows picking up the phone, entering wrong and ‘correct’ codes (223456789, you hear the phone being picked up and hung up. The switch under key 1 is defect…).

Gallery

See pictures below. Clicking each of them will show the complete gallery. Note that each phone consists of the development board and the amplifier of a lowcost Logitech speaker set.

Modified phones

Insides Telephone 1

Insides Telephone 1

Insides Telephone 1

Insides Telephone 2

Insides Telephone 2

Insides Telephone 2

5 thoughts on “Audioplayer based on Xmega AVR

  1. […] sister works at a museum and enlisted his expertise in designing an interactive detective game for kids visiting the museum. The vision was for the kids to discover phone numbers that they could call for clues. Originally […]

  2. […] girlfriend works at a museum and enlisted his expertise in designing an interactive detective game for kids visiting the museum. The vision was for the kids to discover phone numbers that they could call for clues. Originally […]

  3. Ryan Gibson says:

    Hey,

    Great post. Do you have an email I can grab you on? I have a few questions to fire your way.

    Thanks

    Ryan

  4. Cam says:

    Hi,

    Excellent project, thanks for posting it. Can you confirm exactly which of the ALVIDI boards you used, they currently have this lot listed:

    AL-XAVRB V1.3
    AL-XAVRB V2.0
    AL-XSLED
    AL-XSLED_EXT

    Thanks.
    Cam.

    • admin says:

      Hello Cam,
      Thanks for your comment! I’ve built three of these phones, one carries the AL-XAVRB V1.3, the others use the AL-XAVRB V2.0. For the program it makes no difference. If you need some help understanding the code, please let me know!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>