#include #include #include #include #include #include "player.h" #include "spi1.h" #define PLAYER_XRESET_SET() {FIO2SET_bit.P2_11 = 1;} #define PLAYER_XRESET_CLR() {FIO2CLR_bit.P2_11 = 1;} #define PLAYER_DREQ_HIGH() (FIO1PIN_bit.P1_31) #define PLAYER_DREQ_LOW() (!FIO1PIN_bit.P1_31) #define PLAYER_XDCS_SET() {FIO2SET_bit.P2_12 = 1;} #define PLAYER_XDCS_CLR() {FIO2CLR_bit.P2_12 = 1;} #define PLAYER_XCS_SET() {FIO2SET_bit.P2_5 = 1;} #define PLAYER_XCS_CLR() {FIO2CLR_bit.P2_5 = 1;} int player_conn = 0; void delayMicroseconds(CPU_INT32U ms) { while (ms--) { asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); asm(" nop"); } } int await_data_request(void) { CPU_INT32U time_stamp = OSTimeGet(); while (PLAYER_DREQ_LOW()) { if (OSTimeGet() - time_stamp > 1000) { return -1; } } return 0; } u_int16 ReadSci(u_int8 addr) { u_int16 temp; spi1_getSem(); if (await_data_request() != 0) { spi1_freeSem(); return 0x0000; } PLAYER_XDCS_SET(); PLAYER_XCS_CLR(); delayMicroseconds(1); spi1_exchange(0x03); spi1_exchange(addr); delayMicroseconds(10); temp = spi1_exchange(0x00); temp <<= 8; temp += spi1_exchange(0x00); delayMicroseconds(1); PLAYER_XCS_SET(); spi1_freeSem(); return temp; } void WriteSci(u_int8 addr, u_int16 data) { spi1_getSem(); if (await_data_request() != 0) { spi1_freeSem(); return; } PLAYER_XDCS_SET(); PLAYER_XCS_CLR(); delayMicroseconds(1); // tXCSS spi1_exchange(0x02); // Write operation spi1_exchange(addr); // Which register spi1_exchange(data >> 8); // Send hi byte spi1_exchange(data & 0xff); // Send lo byte delayMicroseconds(1); // tXCSH PLAYER_XCS_SET(); await_data_request(); spi1_freeSem(); } int WriteSdi(const u_int8 *data, u_int16 bytes) { spi1_getSem(); PLAYER_XCS_SET(); PLAYER_XDCS_CLR(); while (bytes) { if (await_data_request() < 0) { PLAYER_XDCS_SET(); spi1_freeSem(); return -1; } delayMicroseconds(3); size_t chunk_length = min(bytes, SDI_MAX_TRANSFER_SIZE); bytes -= chunk_length; while (chunk_length--) spi1_exchange(*data++); } PLAYER_XDCS_SET(); spi1_freeSem(); return 0; } /* Read 32-bit increasing counter value from addr. Because the 32-bit value can change while reading it, read MSB's twice and decide which is the correct one. */ u_int32 ReadVS10xxMem32Counter(u_int16 addr) { u_int16 msbV1, lsb, msbV2; u_int32 res; WriteSci(SCI_WRAMADDR, addr+1); msbV1 = ReadSci(SCI_WRAM); WriteSci(SCI_WRAMADDR, addr); lsb = ReadSci(SCI_WRAM); msbV2 = ReadSci(SCI_WRAM); if (lsb < 0x8000U) { msbV1 = msbV2; } res = ((u_int32)msbV1 << 16) | lsb; return res; } /* Read 32-bit non-changing value from addr. */ u_int32 ReadVS10xxMem32(u_int16 addr) { u_int16 lsb; WriteSci(SCI_WRAMADDR, addr); lsb = ReadSci(SCI_WRAM); return lsb | ((u_int32)ReadSci(SCI_WRAM) << 16); } /* Read 16-bit value from addr. */ u_int16 ReadVS10xxMem(u_int16 addr) { WriteSci(SCI_WRAMADDR, addr); return ReadSci(SCI_WRAM); } /* Write 16-bit value to given VS10xx address */ void WriteVS10xxMem(u_int16 addr, u_int16 data) { WriteSci(SCI_WRAMADDR, addr); WriteSci(SCI_WRAM, data); } /* Write 32-bit value to given VS10xx address */ void WriteVS10xxMem32(u_int16 addr, u_int32 data) { WriteSci(SCI_WRAMADDR, addr); WriteSci(SCI_WRAM, (u_int16)data); WriteSci(SCI_WRAM, (u_int16)(data>>16)); } /* Loads a plugin. This is a slight modification of the LoadUserCode() example provided in many of VLSI Solution's program packages. */ void LoadPlugin(const u_int16 *d, u_int16 len) { int i = 0; while (i>= 8; } } void Set16(u_int8 *d, u_int16 n) { int i; for (i=0; i<2; i++) { *d++ = (u_int8)n; n >>= 8; } } /* Hardware Initialization for VS1053. */ int playerInitHardware(void) { /* Write here your microcontroller code which puts VS10xx in hardware reset anc back (set xRESET to 0 for at least a few clock cycles, then to 1). */ // (XRESET) модуля PINSEL4_bit.P2_11 = 0x0; PINMODE4_bit.P2_11 = 0; FIO2DIR_bit.P2_11 = 1; FIO2MASK_bit.P2_11 = 0; PLAYER_XRESET_SET(); // (XDCS) модуля PINSEL4_bit.P2_12 = 0x0; PINMODE4_bit.P2_12 = 0; FIO2DIR_bit.P2_12 = 1; FIO2MASK_bit.P2_12 = 0; PLAYER_XDCS_SET(); // (XCS) модуля PINSEL4_bit.P2_5 = 0x0; PINMODE4_bit.P2_5 = 0; FIO2DIR_bit.P2_5 = 1; FIO2MASK_bit.P2_5 = 0; PLAYER_XCS_SET(); // DREQ (вход контроллера) PINSEL3_bit.P1_31 = 0x0; PINMODE3_bit.P1_31 = 0; FIO1DIR_bit.P1_31 = 0; FIO1MASK_bit.P1_31 = 0; OSTimeDly(1); PLAYER_XRESET_CLR(); OSTimeDly(20); PLAYER_XRESET_SET(); OSTimeDly(50); return 0; } /* Note: code SS_VER=2 is used for both VS1002 and VS1011e */ const u_int16 chipNumber[16] = { 1001, 1011, 1011, 1003, 1053, 1033, 1063, 1103, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Software Initialization for VS1053. Note that you need to check whether SM_SDISHARE should be set in your application or not. */ int player_init(void) { u_int16 ssVer; player_conn = 0; playerInitHardware(); spi1_setSpeed(100000); /* Start initialization with a dummy read, which makes sure our microcontoller chips selects and everything are where they are supposed to be and that VS10xx's SCI bus is in a known state. */ ReadSci(SCI_MODE); /* First real operation is a software reset. After the software reset we know what the status of the IC is. You need, depending on your application, either set or not set SM_SDISHARE. See the Datasheet for details. */ WriteSci(SCI_MODE, SM_SDINEW|SM_RESET); OSTimeDly(10); /* int retry = 0; while (ReadSci(SCI_MODE) != SM_SDINEW) { if (retry++ > 10) { return -8; } WriteSci(SCI_MODE, SM_SDINEW|SM_RESET); OSTimeDly(10); } */ /* A quick sanity check: write to two registers, then test if we get the same results. Note that if you use a too high SPI speed, the MSB is the most likely to fail when read again. */ WriteSci(SCI_AICTRL1, 0xABAD); WriteSci(SCI_AICTRL2, 0x7E57); if (ReadSci(SCI_AICTRL1) != 0xABAD || ReadSci(SCI_AICTRL2) != 0x7E57) { return -1; } WriteSci(SCI_AICTRL1, 0); WriteSci(SCI_AICTRL2, 0); /* Check VS10xx type */ ssVer = ((ReadSci(SCI_STATUS) >> 4) & 15); if (chipNumber[ssVer]) { if (chipNumber[ssVer] != 1053) { return -2; } } else { return -3; } /* Set the clock. Until this point we need to run SPI slow so that we do not exceed the maximum speeds mentioned in Chapter SPI Timing Diagram in the Datasheet. */ WriteSci(SCI_CLOCKF, HZ_TO_SC_FREQ(12288000) | SC_MULT_53_35X | SC_ADD_53_10X); /* Now when we have upped the VS10xx clock speed, the microcontroller SPI bus can run faster. Do that before you start playing or recording files. */ OSTimeDly(10); spi1_setSpeed(10000000); /* Set up other parameters. */ WriteVS10xxMem(PAR_CONFIG1, PAR_CONFIG1_AAC_SBR_SELECTIVE_UPSAMPLE); /* Set volume level at -6 dB of maximum */ WriteSci(SCI_VOL, 0x0c0c); /* We're ready to go. */ player_conn = 1; return 0; } int player_connected(void) { return player_conn; }