In this article Bernard Klinc demonstrates audio playback using the dsPIC on a simple breadboard layout with a free code library for SD card access from Microchip. Bernard will receive a giveaway item of his choice from the hobby parts for articles project here at uCHobby.
This project is mostly around the Microchip MDDFS library (Memory Disk Drive File System). It’s a neat pile of C source code that can manage a FAT12, FAT16 or FAT32 file system and interface to a SD or CF memory card or an IDE hard drive. But best of all its free!
Its downside is only the amount of memory it needs. With all of its features enabled it alone takes up a huge 23KB or flash and 1.4KB of RAM. By disabling features the flash usage can drop drastically but will still at least need 1.3KB of RAM with all extra features disabled
It has taken me some time to get it to compile without errors but once I got it compiled I put in a SD card gave it power for a few seconds, try to read the card and wow there was a txt file created on the card. That was almost too easy!
After some fooling around with it I decided to try and play audio directly from the card. First I needed a way to output an analog voltage out of the pic. The easiest method I know is PWM. As you know PWM is used a lot to control DC motors and things like that but if we use a PWM frequency well out of out hearing range it can output an audio signal. Here a dsPIC30F4013 was used. Luckily it has 4 PWM outputs. So I just used one of those and made it run at about 100 KHz. This pic can do 8 bit accuracy at such a high frequency. Then we just use a RC low pass filter to smooth it out in to a nice analog signal.
As for connecting the card to the pic it connects like a standard SPI device using the usual 4 pins. The pin out is easily found on the web.Note that SD cards are NOT 5V!!! They work on 3.3V. First I simply ran the whole thing on 3.3V but then I wanted to run the dsPIC at its highest speed and it can’t do it on only 3.3V. Because of this I put it on 5V but made a simple regulator with a 3.3V Zener diode to supply the SD card also resistors with series capacitors between the dsPIC and the card so the 5V signals can’t hurt the card. We need to use this simple circuit on the SDO, SCK and CS pins. The SDI pin does not need it because that signal is produced by the SD card so it is 3.3V
Next I needed to know how to get audio data from a *.WAV file. Basically in the beginning of the file it’s described what kind of WAV is it (Sample rate, bit depth, number of channels…) and after that it’s what’s called a data chunk. It’s simply the raw audio data in the format specified in the beginning of the file. The raw data here is actual sound values without any compression or encryption or what so ever (This is considering it’s a standard WAV without any codecs). For more in depth info about the WAV format check links.
All that we need now is some kind of link between the raw data from the WAV file to the PWM output. The reading from the SD card wont happened at a constant speed so we need to get a nicely constant stream of data to the output. This is done by a cyclic buffer. This is a kind of buffer that has no beginning or no end, it’s a circle. So what is happening is that the point that reads from it is moving around the circle at exactly the right speed for the WAVs sample rate (For a 22 KHz WAV file this is exactly 22KB/S) and the reading from the card Is done by a second point that moves at a very non constant speed and what it tries to do it catch the reading point, once it has caught up to that point it has to wait for it to read out some data to make space for new data. When there is free space again it tries to fill it again. So now the data is flowing at a good constant speed in to the PWM module nicely.
And now finally the audio is coming out of the PWM pin on the pic. All that’s left now is plug in the audio jack and have a listen.
What is also needed is to have some code to read the description in the beginning. So it knows how and what at speed to play it. This is not all that difficult. It just needs to check on certain spots of the file. For example 22nd byte contains the number of channels there are in the file (1 = mono, 2 = stereo). But problem is my current hardware can only output mono 8 bit audio. If I utilized all 4 PWMs it would be possible to do 16Bit Stereo, but seems like it’s too slow to play that. But its probably my sloppy coding that’s too slow. But I am going to get my hands on a dsPIC33FJ128GP802. It has a faster CPU and a lot more memory and my favorite a built in audio DAC with its own hardware buffer.
As for the user interface I simply used the com port. I have a ready built RS232-TTL cable so it’s just a matter of connecting it to the RX and TX pins. I have used it for debugging purposes but then made it in to a console that can be accessed with any terminal program like Microsoft HyperTerminal, PuTTY etc… A simple LCD could be quickly stuck on and some buttons to make a user interface without a computer.
As for the quality of the sound, it’s surprisingly good. The sound from it is easily better than a cheap PC sound card!
As for improvements there is a lot of room for that. First of all to get it to play the highest quality WAVs also it shouldn’t be that hard to make it record WAVs using the ADC. Also I have a MP3 decoder chip to make it able to play most MP3 files. A dsPIC is not fast enough for decoding MP3s using its CPU.
8KHz, 11KHz,12KHz, 16KHz, 22KHz,24KHz,32KHz, 44KHz, 48KHz
Stereo or Mono 8Bit or 16Bit
- WAV format : http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
- uCHobby DAC article http://www.uchobby.com/index.php/2008/01/08/arduino-audio-dac-options/
- Similar WAV player http://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.SDMMCWavPlayer