mirror of
https://github.com/dimoniche/solarium.vlad.git
synced 2026-01-30 21:13:31 +03:00
382 lines
8.8 KiB
C
382 lines
8.8 KiB
C
#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;
|
||
}
|