Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

VS100X MP3 Decoder

Status
Not open for further replies.
if you want you can send me one for free and ill play with it and tell you whats happening :D lol

But thats a IC i need to get. I wanted to turn my image viewer into a MP3 player also. I would love for someone to share some code not only to help you but others who might be interested in it.
 
I used a VS1011 to play MP3 files. I did a real quick google search on VS100x to see how similar they are, but I didn't see anything too promising in the first few results (I'm in a hurry right now so I couldn't browse more)... but this thread was at the top of the list :)

Can you see how similar they are and let me know? The code I have I wrote, but it's proprietary so I don't want to just post it. I wouldn't mind helping though.
 
Hey noggin I had a feeling you messed around with them. I'm not sure what the difference is, they are very similar. Right now I just want to get the sine test to work and can't even get that going !
 
I think I completely skipped the sin test and went straight for playing an MP3. Here is the general algorithm used at startup of the board:

  1. Hold VS1011 in reset for 2 mS (hardware reset)
  2. Write 0x0840 to register SCI_MODE to use stream mode and DCS signals as sinc instead of the older bsync mode. Data read at rising edge (MCU changes data at falling edge)
  3. Write 12288 (decimal value) to SCI_CLOCKF since our crystal is 24.576 MHz
  4. Write something to the volume register

The uC was a PIC32, and it looks like everything written to the VS1011 goes in 32-bit chunks, so everything is done using the SPI port in 32 bit mode using the following settings:
SPI1CONbits.CKP = 0; // Clock idles low
SPI1CONbits.SMP = 0; // Sample MISO at middle of output time (rising edge)
SPI1CONbits.CKE = 1; // MOSI data changes on falling edge of clock
SPI1CONbits.MODE16 = 0; // Data mode = 32 bits
SPI1CONbits.MODE32 = 1; // Data mode = 32 bits (4 bytes data)
The baud rate when streaming MP3 data was set to 5 MHz (looks like my notes say 6MHz is max) and 4 MHz when sending control data (notes say 4MHz is max). CS can stay low while writing all 4 bytes, not sure if it MUST stay low or not.

When writing to a register, it looks like the PIC32 sends out a 0x02, then the register address, then the data (the data may be byte swapped... byte swapping always confuses me)

When streaming audio data, the general algorithm I used is

Code:
void Write_MP3_Data(Uint32 *buffer, Uint8 count)
{
Uint8 i;

	Init_SPI_1(MP3_Data);			//settings were described above
	
	MP3_DCS_OUT_ = 0;			// tell the chip we're sending MP3 data
	for (i = 0; i < count; i++)
	{
		SPI1BUF = *buffer;		// Send 4 bytes... we're sending Uint32's here!
		while (!SPI1STATbits.SPIRBF && !MP3_DCS_OUT_);
	}
	MP3_DCS_OUT_ = 1;
}

// Service_MP3_Audio() was called from main every 50mS
void Service_MP3_Audio( void )
{
static vs1011_state_type vs1011_state = VS1011_INIT;
static Int32 bytes_remaining;
static Uint32* pData;
Uint8 buffer[4];

	switch (vs1011_state)
	{
		case VS1011_IDLE:
			if (app_status.play_click)
			{
				vs1011_state = VS1011_PLAYING_SOUND;
				bytes_remaining = SOUND_CLICK_LENGTH;
				pData = (Uint32*)sound_click;
				app_status.play_click = 0;
			}
			else if (app_status.play_sound28)
			{
				vs1011_state = VS1011_PLAYING_SOUND;
				bytes_remaining = SOUND_28_LENGTH;
				pData = (Uint32*)sound_28;
				app_status.play_sound28 = 0;
			}	
			break;
			
		case VS1011_PLAYING_SOUND:
			// if MP3_DREQ_IN is high, then at LEAST 32 bytes
			// of data are free in the VS1011
			while (MP3_DREQ_IN && bytes_remaining > 0)
			{
				// Get the byte ordering correct!
				buffer[0] = (Uint8)(*pData>>24);
				buffer[1] = (Uint8)(*pData>>16);
				buffer[2] = (Uint8)(*pData>>8);
				buffer[3] = (Uint8)(*pData>>0);
				
				Write_MP3_Data( (Uint32*)buffer, 1 );
				pData++;
				bytes_remaining -= 4;
			}
			
			if (bytes_remaining <= 0)
				vs1011_state = VS1011_IDLE;
			break;
	}	
}

To make the MP3 files, I opened an MP3 in a hex editor (XVI32 Hex Editor), copied and pasted the hex data to jEdit (awesome open source java based text editor), and used macros to format everything to look like an array of data.

This is my click sound:
Code:
#include "sounds.h"

const Uint8 sound_click[] __attribute__((aligned(4))) = {
0x49, 0x44, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x43, 0x4F,
0x4E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x6C, 0x75, 0x65, 0x73,
0xFF, 0xF2, 0x84, 0x00, 0xE1, 0x18, 0x00, 0x00, 0x00, 0x01, 0xA4, 0x00, 0xA0,
0x00, 0x00, 0x11, 0xF9, 0x7E, 0xA8, 0x03, 0x43, 0x18, 0x00, 0x60, 0x18, 0xBD,
0x11, 0x11, 0x11, 0xDD, 0xDD, 0xDD, 0xCF, 0x7F, 0x88, 0x88, 0x9C, 0xFA, 0xEE,
0xE7, 0xBB, 0xBB, 0xE8, 0x89, 0xA0, 0x00, 0x00, 0x00, 0x87, 0x03, 0x03, 0x30,
0xE2, 0xDF, 0xFF, 0xE2, 0x7D, 0x77, 0x7E, 0xBB, 0xBB, 0x9F, 0x11, 0xC3, 0x81,
0x81, 0xBC, 0x44, 0xC2, 0x00, 0x00, 0x00, 0x08, 0x01, 0x87, 0xD6, 0x0F, 0x87,
0xF5, 0x02, 0x1E, 0x0F, 0x9F, 0x2E, 0xFE, 0x0F, 0x83, 0xEF, 0xE0, 0x81, 0xCF,
0xFC, 0x1F, 0x07, 0xDE, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80,
0xC0, 0x60, 0x30, 0x18, 0x00, 0x3F, 0xE0, 0x03, 0x66, 0xF0, 0xF4, 0x80, 0xA0,
0x1F, 0x12, 0xE1, 0x3C, 0x78, 0x26, 0x18, 0x51, 0x83, 0xFB, 0xF8, 0x84, 0x21,
0x76, 0x85, 0xF2, 0x12, 0x5F, 0xF0, 0x1E, 0x50, 0x0D, 0x0B, 0x10, 0x37, 0xB0,
0x80, 0xDE, 0x61, 0x03, 0x02, 0xB3, 0xFF, 0x00, 0x63, 0x41, 0x70, 0x82, 0x7B,
0x14, 0x10, 0x18, 0x60, 0x20, 0x98, 0x8F, 0xFF, 0x0F, 0x98, 0x0C, 0x80, 0x20,
0x0A, 0x56, 0x00, 0x08, 0xC0, 0xC2, 0xC0, 0x03, 0x22, 0xDC, 0x0D, 0x9A, 0x8F,
0xFF, 0xC0, 0xD4, 0x33, 0x04, 0x85, 0x01, 0x8A, 0x06, 0x0D, 0xFF, 0xF2, 0x84,
0x00, 0xD8, 0x78, 0x61, 0x00, 0x00, 0x01, 0xA4, 0x00, 0xC0, 0x00, 0x00, 0x2B,
0x33, 0x6F, 0x2A, 0x5F, 0x94, 0xA2, 0x03, 0xF8, 0xA6, 0x03, 0xC0, 0x04, 0x43,
0x87, 0xC0, 0x18, 0xFF, 0xFF, 0xFE, 0x54, 0x0F, 0xD8, 0x47, 0x41, 0xE9, 0x85,
0xF0, 0x10, 0x54, 0x2C, 0xF0, 0x64, 0x70, 0xF8, 0x85, 0xF8, 0xE1, 0x22, 0xFF,
0xFF, 0xFF, 0xE3, 0xA4, 0x5C, 0x88, 0x09, 0x44, 0x48, 0x08, 0xD1, 0x43, 0x0C,
0x98, 0xB9, 0x88, 0xE1, 0xFC, 0x9C, 0x2F, 0x93, 0x08, 0x17, 0xFF, 0xFF, 0xFF,
0xFF, 0xC9, 0xC2, 0xA1, 0xD2, 0xF4, 0x90, 0x76, 0x24, 0x8C, 0x0D, 0xCB, 0xC4,
0xD9, 0x34, 0x68, 0x05, 0x06, 0x06, 0x6E, 0xF5, 0xAB, 0x6E, 0x49, 0x54, 0x04,
0x04, 0x4A, 0xAA, 0xAB, 0x33, 0x33, 0x33, 0x37, 0xAA, 0xAA, 0xAA, 0xA9, 0x75,
0x54, 0xB6, 0x66, 0x2F, 0xFE, 0x33, 0x17, 0x18, 0xFA, 0xAA, 0xDF, 0xFC, 0x66,
0x5F, 0xFF, 0xF8, 0xCC, 0xCD, 0xEA, 0xBA, 0xAA, 0xAF, 0xFE, 0xCC, 0xC7, 0xFF,
0x55, 0x55, 0x55, 0x7E, 0x33, 0x33, 0x33, 0x06, 0x02, 0x50, 0x55, 0xD9, 0x60,
0x68, 0x1A, 0x0E, 0xF0, 0x54, 0x15, 0x06, 0x81, 0xA3, 0xDC, 0x4A, 0x0A, 0x82,
0xB8, 0x34, 0x7A, 0x25, 0x05, 0x41, 0x57, 0x60, 0xD3, 0xE0, 0xAB, 0xBE, 0x54,
0x37, 0xA8, 0x1A, 0x0D, 0x78, 0x34, 0x0D, 0xFF, 0xF2, 0x84, 0x00, 0x29, 0x9F,
0x5D, 0x00, 0x00, 0x01, 0xA4, 0x00, 0xE0, 0x00, 0x00, 0x1A, 0x69, 0xDA, 0xAD,
0x97, 0xC3, 0x18, 0x02, 0x3F, 0x12, 0x82, 0xA0, 0xA8, 0x2C, 0xF9, 0x60, 0x68,
0x35, 0x82, 0xA0, 0xB5, 0x4C, 0x41, 0x4D, 0x45, 0x33, 0x2E, 0x39, 0x38, 0x2E,
0x32, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4C, 0x41, 0x4D, 0x45,
0x33, 0x2E, 0x39, 0x38, 0x2E, 0x32, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0xFF, 0xF2, 0x84, 0x00, 0xD0, 0x26, 0x9C, 0x00, 0x00,
0x01, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x48, 0x00, 0x00, 0x00,
0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4C, 0x41, 0x4D, 0x45, 0x33, 0x2E, 0x39,
0x38, 0x2E, 0x32, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0xFF, 0xF2, 0x84, 0x00, 0x1D, 0x9F, 0xFF, 0x00, 0x00, 0x01, 0xA4, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x48, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };

/*** End of File ***/

and this is the sounds.h header file
Code:
/* **** Global Definitions **** */
#define SOUND_28_LENGTH				0x5660
#define SOUND_CLICK_LENGTH			0x03D0

/* **** Gobal Function Prototypes **** */

/* **** Global Variables **** */

extern const Uint8 sound_28[];
extern const Uint8 sound_click[];



/*** End of File ***/

Hope some of that helps...
 
Last edited:
Hey guys, a good news update, I got it to work!
The main culprit was the 24f's SPI module which i was not used to. It still is a problem as this code does not work:

Code:
void SPIPutChar(char c){
	MP3_SPI_IF = 0;
	MP3_SPIBUF  = c;              // write command
	while(!MP3_SPI_IF);
        MP3_SPI_IF = 0;
}

where MP3_SPI_IF = ISR0bits.SPI1IF

instead of the above i just wait the expected time in a delay before sending the next bit, but i would much rather get the above working.

Any input is appreciated :D
 
This is a routine I used to read a 16 bit value from an ADC with a PIC24F

Code:
Uint16 Read_Adc( void )
{
Uint16 value = 0;

	cs_adc_pin = 0;							// Select the ADC
	Delay_Microseconds(1);	
	// Using the SPI, read two bytes from the ADC
	SPI1BUF = 0;								// Transmit
	while (SPI1STATbits.SPIRBF == 0);	// Wait for the high byte to be received
	value = SPI1BUF<<8;						// Read the high byte
	SPI1BUF = 0;								// Transmit
	while (SPI1STATbits.SPIRBF == 0);	// Wait for the low byte to be received
	value |= (Uint8)SPI1BUF;				// Read the low byte
	Delay_Microseconds(1);	
	cs_adc_pin = 1;							// Deselect the ADC
		
	return value;
}

Have you set the SPI peripheral to generate an interrupt when the transmit/receive is complete? Check the SISEL bits.

Here is my SPI init:

Code:
	RPOR11bits.RP23R = 8;		// SPI1 clock is on RP23
	RPOR11bits.RP22R = 7;		// SPI1 data output is on RP22
	RPINR20bits.SDI1R = 24;		// SPI1 data input is on RP24
	SPI1CONbits.DISSDO = 1;		// SDO not controlled by the module
	
	SPI1STATbits.SPISIDL = 1;	// Do not operate SPI while idle
	SPI1CONbits.MSTEN = 1;		// Enable master mode
	SPI1CONbits.SPRE = 4;		// Secondary prescale 4:1
	SPI1CONbits.PPRE = 0;		// Primary prescale 16:1
	SPI1CONbits.CKE = 1;			// Serial output changes on clk transition from active to idle
	SPI1CONbits.CKP = 0;			// Idle state for clk is low
	SPI1STATbits.SPIROV = 0;	// Clear receive overflow flag
//	SPI1STATbits.SISEL = 5;		// Generate interrupt when transmit is complete
	SPI1STATbits.SPIEN = 1;		// Enable SPI1

I see that I have commented out the interrupt-on-complete line though. I probably did that because I wasn't using the interrupt flag to end the while loop.

I've also found that the SPI peripheral does NOT like it if you don't read from the SPI buffer whether you want the data or not as it will cause an overflow. I would suggest that you declare a volatile variable and read the spi register into it to keep from getting overflows any time you write to it.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top