| 
View
 

AvrSound

This version was saved 20 years, 10 months ago View current version     Page history
Saved by PBworks
on October 26, 2005 at 9:52:58 pm
 

Standalone AVR Music Player "Sound Bug"

 

Using the term 'music' liberally here, it will play a squeaky, but recognizable stream of audio, generated from MIDI files.

 

It's a satisfying little project that is a nice change from the typical beginner embedded controller blinking LED project(s).

 

You can't get any simpler than this: a piezo buzzer, a power supply (3x1.5 AA), a breadboard, and an AVR (ATmega16, but almost any will do).

 

 

You'll also need WinAVR or avr-gcc on Linux.

 

This code is lifted from the AvrButterfly originally from Atmel, and as modified and ported by MartinThomas to GCC. He's got tons of info on his page and I've gone back to it many many times as a resource.

 

I've made a few changes. I've extracted out only the essential sound and timer files from the Butterfly source code, and hacked them mercilessly to remove non-essential code, and code I did not understand. Which is a fair amount :-). I've also separated the songs file from the sound generation file.

 

Once loaded, wired, and powered, it will play an audio file repeated. In this case, Invention #8 by Bach.

I'm still learning how to use the clock prescaler on the ATmega16, so I made life simple and used AVRStudio to adjust the clock down to 1MHz to make it match the prescaled value from AvrButterfly

 

http://avrprog.pbwiki.com/f/Makefile

http://avrprog.pbwiki.com/f/sound.c

http://avrprog.pbwiki.com/f/sound.h

http://avrprog.pbwiki.com/f/songs.c

http://avrprog.pbwiki.com/f/songs.h

http://avrprog.pbwiki.com/f/timer0.c

http://avrprog.pbwiki.com/f/timer0.h

 

The modified sound.c automatically plays the first song in the Songs in songs.c in sound.c. It would be small change to make it play a different song or a song triggered by a button press.

 

MIDI File Conversion

 

In order to get access to a large list of music and audio, I made a little program to convert arbitrary MIDI files into the byte stream required for the AVR sound.c file.

 

This is the original MIDI file, available from many sites...

http://avrprog.pbwiki.com/f/invent8.mid

 

This is a CSV (CommaSeparatedFile) file extracted from the MIDI file above using a program called MIDICSV.

http://avrprog.pbwiki.com/f/invent8.csv

 

The CSV file is further converted into a ".h" include file using the program m2b

http://avrprog.pbwiki.com/f/invent8.h

 

The tiny program m2b converts the CSV into include file fragment which can be incorporated (by hand) into the songs.c and songs.h file. The example is which is a C file called [http://avrprog.pbwiki.com/f/invent8.h]. This file may be included directly into sound.c into the sound.c file.

 

Compression

 

The original sound file separated the duration and tone into separate words. I've combined them (making them unreadable, but more compressed) to allow putting songs nearly 2x as long in the same page. The compression scheme is simple and reversible - recognizing that only a few of the note durations were actually used in practice, I enumerated them 1 through N, and shifted them 11 bits left into the bits positions above 11, leaving bits 1-11 for the frequency. To unencode this, the lower bits are masked off for the frequency, further compression is possible, as is using external memory of course.

 

Compile/Build/Porting

 

The Makefile is set for the ATmega16. As a beginning AVR programmer, I found it somewhat cryptic to figure out how to port the timer code in sound.c for the ATmega8515 and ATmega169 in the butterfly. To convert between the original ATmega169 code and the ATmega16, I made several changes in sound.c and timer0.c

 

  • changed references from TIMSK0 to TIMSK
  • changed references from OCR0A to OCR0, and OCIE0A to OCIEOA
  • removed references to timer2
  • changed output port references for OC1A from PORTB (on the '169) to PORTD (on the '16).
  • changed port direction register from DDRB to DDRD (portb to portd)

 

I'm sure there's a excellent reason why Atmel is unable to keep these more consistent, but I'm not aware of it... :-)

There does not appear to be an obvious way to write portable code that uses timers, signals, interrupts that I've come across yet, even in C, let along assembler.

 

The Hardware

 

  • Put your AVR on a breadboard and connect power and ground appropriately.
  • Connect one end of the speaker (piezo buzzer) to ground and the other to OC1A out. This appears to be inconsistently assigned to one of the data output pins so look for OC1A.

 

Audio should play right away.

 

Trouble Shooting

 

  • Is your AVR running at 1Mhz (or did you figure out how to set the prescaler)?
  • Did you check that you got the right pin for OC1A?
  • Did you set the compile flag MCU in the Makefile for your appropriate AVR processor?

 

Apologies in advance for errors/omissions. I found the lack of beginner AVR material a bit of an uphill battle and I'm hoping that by putting some works in progress that have helped me learn I can save someone else a little time. Good luck!

 

To Be Done

 

  • Break out audio files into separate compile file (easy)
  • Load it from MMC card
  • Integrate Roman Black's cool 1-bit audio?

 

Contact

 

contact newsaccount dot h at gmail dot com with questions or comments

Comments (0)

You don't have permission to comment on this page.