382 lines
8.8 KiB
C
Raw Permalink Blame History

#include <includes.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#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<len) {
unsigned short addr, n, val;
addr = d[i++];
n = d[i++];
if (n & 0x8000U) { /* RLE run, replicate n samples */
n &= 0x7FFF;
val = d[i++];
while (n--) {
WriteSci(addr, val);
}
} else { /* Copy run, copy n samples */
while (n--) {
val = d[i++];
WriteSci(addr, val);
}
}
}
}
void Set32(u_int8 *d, u_int32 n) {
int i;
for (i=0; i<4; i++) {
*d++ = (u_int8)n;
n >>= 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) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PINSEL4_bit.P2_11 = 0x0;
PINMODE4_bit.P2_11 = 0;
FIO2DIR_bit.P2_11 = 1;
FIO2MASK_bit.P2_11 = 0;
PLAYER_XRESET_SET();
// (XDCS) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PINSEL4_bit.P2_12 = 0x0;
PINMODE4_bit.P2_12 = 0;
FIO2DIR_bit.P2_12 = 1;
FIO2MASK_bit.P2_12 = 0;
PLAYER_XDCS_SET();
// (XCS) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PINSEL4_bit.P2_5 = 0x0;
PINMODE4_bit.P2_5 = 0;
FIO2DIR_bit.P2_5 = 1;
FIO2MASK_bit.P2_5 = 0;
PLAYER_XCS_SET();
// DREQ (<28><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
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;
}