/* ********************************************************* VS1002 MP3 breakout board test routine. This program contains basic functions to communicate with the VS1002 MP3 decoder and play a test tone. Owen Osborn, Spark Fun electronics, 10-12-05 ********************************************************* */ /* ********************************************************* Function declarations ********************************************************* */ void delay(void); // NOTE: the vs1002 chip is configured in SM_SDISHARE mode. pg 16 data sheet unsigned short int vs1002_SCI_read(unsigned char); void vs1002_SCI_write(unsigned char, unsigned short int); // this performs an SDI write (cs inverted). pg 16 void vs1002_sineTest(unsigned char); // these are specific to the LPC2138 ARM MCU and don't have anything to do with // the MP3 chip void Initialize(void); void feed(void); void IRQ_Routine (void) __attribute__ ((interrupt("IRQ"))); void FIQ_Routine (void) __attribute__ ((interrupt("FIQ"))); void SWI_Routine (void) __attribute__ ((interrupt("SWI"))); void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF"))); /********************************************************** Header files **********************************************************/ #include "LPC21xx.h" /********************************************************** MAIN **********************************************************/ int main (void) { // configure SPI0 pins, master mode PINSEL0 = 0x1500; // SPI pin connections S0SPCCR = 32; // SCK = 1 MHz, counter > 8 and even S0SPCR = 0x20; // Master, no interrupt enable IODIR0 |= 0x00000080; IOSET0 |= 0x80000080; // cs high to start vs1002_SCI_write(0x00, 0x0c20); // sets sci_mode register, SM_SDINEW, SM_SDISHARE // SM_TESTS. pg 25, 26 vs1002_sineTest(170); // test tone frequency (pg 35) for (;;) { } } //main unsigned short int vs1002_SCI_read(unsigned char address) { unsigned short int temp; IOCLR0 |= 0x00000080; // cs low S0SPDR = 0x03; // read command while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = address; // address here while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0x00; while (!(S0SPSR & 0x80)) ; // wait for transfer completed temp = S0SPDR ; // get data here MSBs temp <<= 8; S0SPDR = 0x00; while (!(S0SPSR & 0x80)) ; // wait for transfer completed temp += S0SPDR; // get data here LSBs IOSET0 |= 0x00000080; // cs high return temp; } void vs1002_SCI_write(unsigned char address, unsigned short int data) { IOCLR0 |= 0x00000080; // cs low S0SPDR = 0x02; // read command while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = address; // address here while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = data >> 8; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = data; while (!(S0SPSR & 0x80)) ; // wait for transfer completed IOSET0 |= 0x00000080; } // This is SDI write so cs is reversed (internally inverted), pg 21 // for a sine wave test @ 5168 hz, send sequence: 0x53, 0xEF, 0x6E, 126, 0, 0, 0, 0 void vs1002_sineTest(unsigned char pitch) { IOSET0 |= 0x00000080; // cs HIGH S0SPDR = 0x53; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0xEF; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0x6E; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = pitch; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0; while (!(S0SPSR & 0x80)) ; // wait for transfer completed S0SPDR = 0; while (!(S0SPSR & 0x80)) ; // wait for transfer completed IOCLR0 |= 0x00000080; // cs LOW } void delay(void){ unsigned int count; for(count = 0; count < 10000; count++){ } } /********************************************************** Initialize **********************************************************/ #define PLOCK 0x400 void Initialize(void) { // Setting the Phased Lock Loop (PLL) // ---------------------------------- // // Olimex LPC-P2106 has a 14.7456 mhz crystal // // We'd like the LPC2106 to run at 53.2368 mhz (has to be an even multiple of crystal) // // According to the Philips LPC2106 manual: M = cclk / Fosc where: M = PLL multiplier (bits 0-4 of PLLCFG) // cclk = 53236800 hz // Fosc = 14745600 hz // // Solving: M = 53236800 / 14745600 = 3.6103515625 // M = 4 (round up) // // Note: M - 1 must be entered into bits 0-4 of PLLCFG (assign 3 to these bits) // // // The Current Controlled Oscilator (CCO) must operate in the range 156 mhz to 320 mhz // // According to the Philips LPC2106 manual: Fcco = cclk * 2 * P where: Fcco = CCO frequency // cclk = 53236800 hz // P = PLL divisor (bits 5-6 of PLLCFG) // // Solving: Fcco = 53236800 * 2 * P // P = 2 (trial value) // Fcco = 53236800 * 2 * 2 // Fcc0 = 212947200 hz (good choice for P since it's within the 156 mhz to 320 mhz range // // From Table 19 (page 48) of Philips LPC2106 manual P = 2, PLLCFG bits 5-6 = 1 (assign 1 to these bits) // // Finally: PLLCFG = 0 01 00011 = 0x23 // // Final note: to load PLLCFG register, we must use the 0xAA followed 0x55 write sequence to the PLLFEED register // this is done in the short function feed() below // // Setting Multiplier and Divider values PLLCFG=0x23; feed(); // Enabling the PLL */ PLLCON=0x1; feed(); // Wait for the PLL to lock to set frequency while(!(PLLSTAT & PLOCK)) ; // Connect the PLL as the clock source PLLCON=0x3; feed(); // Enabling MAM and setting number of clocks used for Flash memory fetch (4 cclks in this case) MAMCR=0x2; MAMTIM=0x4; // Setting peripheral Clock (pclk) to System Clock (cclk) VPBDIV=0x1; } void feed(void) { PLLFEED=0xAA; PLLFEED=0x55; } /* Stubs for various interrupts (may be replaced later) */ /* ---------------------------------------------------- */ void IRQ_Routine (void) { while (1) ; } void FIQ_Routine (void) { while (1) ; } void SWI_Routine (void) { while (1) ; } void UNDEF_Routine (void) { while (1) ; }