Interfacing VS1053 audio encoder/decoder module with PIC using SPI
To fulfill my wish of building an MP3 player on top of a 16-bit PIC (PIC24FJ64GA002), I purchased a VS1053 audio encoder/decoder module from eBay. The VS1053, manufactured by VLSI, is capable of decoding WAV/MP3/WMA/OGG/AAC/MIDI files, as well as FLAC format with the help of a software plugin. It is also capable of recording audio, either via the Line In input, or via a microphone, which comes installed in the breakout board that I purchased.
Module pinout
The front and back of the module, with the 5×2 connection header:
To be able to use it on a breadboard for prototype development, I made a small breakout board for the connection header using a small piece of stripboard. The pinout description for the connection header is below:
MOSI - Master Out Slave In
MISO - Master In Slave Out
SCK - SPI Clock Signal
XCS - Send Command (Active Low)
XDCS - Send Data (Active Low)
XRST - Reset (Active Low)
DREQ - Data Request
The module uses Serial Peripheral Interface (SPI) to communicate with the microcontroller. I used the code from here and adapted it to work with my PIC24FJ64GA002 hardware SPI modules. The completed modified code can be downloaded here.
Audio playback
The VS1053 has a few registers which control its operations. Among them, the more important registers are:
SCI_MODE - Controls the operation of the module
SCI_STATUS - Controls information on the current status of the module
SCI_BASS - Controls the bass boosting DSP algorithm used for playback
SCI_CLOCKF - Controls the chip clock frequency
SCI_VOL - Controls playback volume
To use the VS1053 module to play and record audio files, I converted the Adafruit‘s Arduino library for the VS1053 to compile under Microchip C30 compiler. To initialize the module, set the microcontroller SPI speed to 1MHz, pull down pin XRST for a short while to perform a reset and then read the value of register SCI_MODE, which should contain the default value of 0x4800:
// primary scaler 4:1, secondary scaler 4:1 @ 1MHz
spi2Init(0b00010010);
//Deselect Control
MP3_XCS = 1;
//Deselect Data
MP3_XDCS = 1;
// hardware reset
MP3_RESET = 0;
delay_ms(10);
MP3_RESET = 1;
delay_ms(10);
//Set initial volume (20 = -10dB)
vs1053_SetVolume(volDefault, volDefault);
//Read the SCI_MODE register
vs1053_ReadRegister(SCI_MODE);
When ready for audio playback, write to SCI_CLOCKF register to set the multiplier and increase the clock speed of the VS1053, followed by increasing the PIC SPI clock speed:
//increase the VS1053 internal clock multiplier and up our SPI
vs1053_WriteRegister(SCI_CLOCKF, 0x60, 0x00); //Set multiplier to 3.0x
// Internal clock multiplier is now 3x.
// Therefore, max SPI speed is 5MHz. 4MHz will be safe.
// primary scaler 1:1, secondary scaler 4:1.
SPI2CON1 = SPI2CON1 | 0b00010011;
The above code assumes that the PIC is running at 32MHz. When the setup is completed, supported files can be playing by simply sending data to the module via SPI:
void vs1053_play(unsigned char* data, unsigned int len)
{
unsigned char *p;
int i;
p = &data[0]; // Point "p" to the beginning of array
while(p <= &data[len - 1]) {
while(!MP3_DREQ_IN) {
//DREQ is low while the receive buffer is full
//You can do something else here, the bus is free...
//Maybe set the volume or whatever...
}
//Once DREQ is released (high) we can now send 32 bytes of data
MP3_XDCS = 0; //Select Data
spi2Write(*p++); // Send SPI byte
MP3_XDCS = 1; //Deselect Data
}
while(!MP3_DREQ_IN) ; //Wait for DREQ to go high indicating transfer is complete
MP3_XDCS = 1; //Deselect Data
}
Except for a few problems with SPI setup on my PIC24, my completed code works upon first try. The played music sounds very clear and the output current is strong enough to be able to be listened through a headphone. Using Microchip MDD library, I was able to interface the PIC with my 128MB SD card and play WAV/MP3/WMA/OGG/AAC files from the card smoothly. For MIDI files, only midi type 0 (single track) files are supported by the VS1053. If your MIDI files are of type 1 (multi-track), you’ll need to convert them to type 0 before they can be played. You can download many sample MIDI type 0 and type 1 files for testing here.
According to the datasheet, FLAC files are supported by loading a software plugin. I have not tried this, however.
Unexpected problem: floating XTEST pin!
In the midst of the experiment I suddenly realized that my VS1053 module stopped working. It could no longer play any audio file and SCI_MODE always read 65424 (0xFF90) upon power on, instead of the default 0x4800. When this happened, other SPI read/write operations still appeared to be working fine, e.g. written values could still be read back properly. Attempting to write the default value of 0x4800 to SCI_MODE was successful, but the module still could not play any audio data.
I decided to put the board away for a while, remove the power and try again. Surprisingly, everything worked again upon the first try, but only exactly once! Upon the second run the module exhibited the same beaviour (0xFF90 for SCI_MODE at startup) again. I tried again with a fresh VS1053 module and again, it could only work once.
What was exactly the problem? The module could not have been totally broken because SPI read/write was still working fine. And it was also unlikely that two different modules were damaged in exactly the same manner. At this point I suspected that since some parts of the code were incorrect, it could have altered the contents of non-volatile memory of the VS1053 and causing permanent damage. Searching the Internet revealed that other people have similar inconsistent behaviors and suspected non-volatile memory corruption of the VS1053. However, posts on the VSDSP forum confirmed that the VS1053 does not have non-volatile memory, so the problem must have been something electrical.
The real problem, after much research effort, is the XTEST pin on the VS1053. This pin must be connected to VDD for things to work consistently. Many clone boards, including earlier versions of the Sparkfun VS1053 boards and those sold on eBay, leave the XTEST pin unconnected, leading to unspecified behavior. I referred to the datasheet for the location of XTEST, which is pin 32 in the LQFP-48 package:
After several checks I confirmed that pin XTEST was indeed floating. Take note that since the PCB may be multi-layered, you can’t judge whether a pin is floating just because it looks unconnected as it may be connected via the hidden layers of the PCB. Although the pins are tiny and appear very difficult to solder using a generic soldering iron, I was lucky as all I needed to do was to connect XTEST to VDD, which happens to be the neighboring pin 31 (CVDD3). A single drop of solder between the two pins is all that is needed and the modified board is below (the soldered pins are in red):
With this modification, the board works well and there are no longer any intermittent problems. If you still have problems, make sure that GPIO0 and GPIO1 pins are also connected to GND. Some boards have GPIO0 connected to GND while GPIO1 connected to VDD and the module will boot up in real-time MIDI mode instead.
Audio recording
The module supports recording, either via the on-board microphone or via the Line In input. Natively, Pulse Code Modulation (PCM) encoding is supported, in either linear (uncompressed) or ADPCM (compressed). Encoding into OGG format is supported via software plugin. PCM are encoded in 16-bit little endian format.
To enter recording mode, set the bit SM_ADPCM and SM_RESET of the SCI_MODE register. Bit SM_LINE1 may be set if recording via Line In, otherwise clear it to record via the microphone. Page 53 of the datasheet explains this in details. Take note that if you’re recording via the microphone, set SCI_AICTRL3 bit 0-1 into left channel mode, otherwise the default is stereo (both channels) and the output audio will be distorted since the microphone provides single channel (mono) only.
I tried to perform a linear PCM recording and write the data to an SD card. At 8kHz and 16-bit, the output file consumes approximately 16KB per second. I performed a benchmark of the FSfwrite function of the MDD library by opening a file and appending 0xFF to it. The speed is approximately 18KB/s with the PIC running as 32MHz. The actual writing speed when recording will be lower as the PIC is also busy communicating with the VS1053 to retrieve the audio data. As a result, the recorded audio file appears to be choppy and it seems further optimization is needed for recording to work properly.
As this is a hobby project, I decided not to proceed with improving the recording performance. Using this module for audio playback should be good enough on a PIC24. The C30 code to play audio files using VS1053 can be downloaded here for those who are interested.
See also
do you use 5V MCU ?
Hi,
I am using the PIC24FJ64GA002 which is a 3.3V MCU as the VS1053 works at 3.3V only. If you use a 5V MCU you may need a level converter to make it work.
Hello ,
Nice write up.
I am working on Adafruit VS1053B .. Could you send me your code so that I can port it to STM32F4 which I am currently using here.
Thanks,
Pradeep Ch.
Hi,
The code is already provided at the end the article. Let me know if you have any questions.
Hi,
Which kind of supply do you use for the SD1053? Do you use a regulated AC/DC (5V2), a regulated 5V0 or something else?
I ask me how the shield will react having 5v2.
Cheers, MA
Hi,
My VS1053V module requires 3.3V. I simply feed a 9V battery through a 78LS33 to get 3.3V for the module. It is possible that your SD1053 module requires a different input voltage (e.g. 5V), depending on board design. Check with the seller or the website where you purchased the board for more details on this.
Hi,
Yes, my has 5V input.
How is your SPI configuration (SPI_mode=0, I-sample Middle, etc ) ? I’m having troubles reading the registers and playing data (XTEST is not the problem).
The pinout for the VS1053 – is it from the underside? So when I turn upside the pinout is reversed, is that right. I don’t want to connect 5V to the wrong pin. Thanks
The pinout of the connector might be different depending on where you bought the board from. If you are unsure, look for the pinout of the main IC chip or voltage regulator on the board and use a multimeter to verify that the 5V and GND pins are connected properly before applying power.
Hi ToughDev,
Though this is an old post, I was wondering if you had a datasheet for your VS1053 module. I have the exact same module, but it did not come with a datasheet and I could not find one online. Any help would be much appreciated.
Best,
Andrew
Hi Andrew,
You can find the datasheet and other information from here: vlsi.fi/en/products/vs1053.html
It took me some hour to see GPIO1 should be pull low.
I work around as make GPIO1 as output high, and it work.
Then I see your post , with XTEST need to be corrected too.
Next time I’ll buy a good module to save time.