.info: http://210.240.226.206/%A4%FD%E5f%A4%AF%A6%D1%AEv/20100201/src/vs10xx.c
XxXxXxXxXxXxXxXxXxXxXxXx vs10xx.c XxXxXxXxXxXxXxXxXxXxXxXx
/** \file vs10xx.c
* Functions for interfacing with the mp3 player chip.
* \todo safe rewind
* \todo VS1003 WMA "wma-bytes-left" variable adjustment at ff/rew
*/
#include "vs10xx.h"
#include "lcd.h"
#include "filesys.h"
#include "storage.h"
#include "ui.h"
#define SKIP_PLUGIN_VARNAME
const unsigned short patch[] = {
#include "vs1053b-patches.plg"
};
void LoadUserPatch(void) {
int i = 0;
ConsoleWrite(" LoadUserPatch ");
while (i<sizeof(patch)/sizeof(patch[0])) {
unsigned short addr, n, val;
addr = patch[i++];
n = patch[i++];
if (n & 0x8000U) { /* RLE run, replicate n samples */
n &= 0x7FFF;
val = patch[i++];
while (n--) {
Mp3WriteRegister(addr, val>>8, val & 0xff);
}
} else { /* Copy run, copy n samples */
while (n--) {
val = patch[i++];
Mp3WriteRegister(addr, val>>8, val & 0xff);
}
}
}
Delay(1);
while (!MP3_DREQ)
;
}
/** Read the 16-bit value of a VSer */
unsigned int Mp3ReadRegister (unsigned char addressbyte){
unsigned int resultvalue = 0;
Mp3SelectControl();
SPIPutCharWithoutWaiting(VS_READ_COMMAND);
SPIPutChar((addressbyte));
SPIPutChar(0xff);
SPIWait();
resultvalue = (SPI_RESULT_BYTE) << 8;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
resultvalue |= (SPI_RESULT_BYTE);
Mp3DeselectControl();
return resultvalue;
}
/** Soft Reset of VS10xx (Between songs) */
void Mp3SoftReset(){
/* Soft Reset of VS10xx */
Mp3WriteRegister (SPI_MODE, 0x08, 0x04); /* Newmode, Reset, No L1-2 */
Delay(1);
while (!MP3_DREQ) /* wait for startup */
;
/* Set clock register, doubler etc. */
Mp3WriteRegister(SPI_CLOCKF, 0xa0, 0x00);
while (!MP3_DREQ)
;
LoadUserPatch();
}
/** Soft Reset of VS10xx (Between songs) */
void Mp3SoftResetWithoutPatch(){
/* Soft Reset of VS10xx */
Mp3WriteRegister (SPI_MODE, 0x08, 0x04); /* Newmode, Reset, No L1-2 */
Delay(1);
while (!MP3_DREQ) /* wait for startup */
;
/* Set clock register, doubler etc. */
Mp3WriteRegister(SPI_CLOCKF, 0xa0, 0x00);
while (!MP3_DREQ)
;
}
/** Reset VS10xx */
void Mp3Reset(){
//ConsolePutChar(13);
Mp3PutInReset();
Delay(1);
/* Send dummy SPI byte to initialize atmel SPI */
SPIPutCharWithoutWaiting(0xFF);
/* Un-reset MP3 chip */
Mp3DeselectControl();
Mp3DeselectData();
Mp3ReleaseFromReset();
while (!MP3_DREQ)
;
#if 0
ConsoleWrite("ClockF:");
ConsolePutUInt(Mp3ReadRegister(SPI_CLOCKF));
ConsolePutChar(13);
#endif
/* Set clock register, doubler etc. */
Mp3WriteRegister(SPI_CLOCKF, 0xa0, 0x00);
Delay(1);
/* Wait for DREQ */
while (!MP3_DREQ)
;
#if 0
ConsoleWrite("ClockF:");
ConsolePutUInt(Mp3ReadRegister(SPI_CLOCKF));
ConsolePutChar(13);
Mp3WriteRegister(SPI_WRAMADDR, 0xc0, 0x13);
ConsoleWrite("0xC013:");
ConsolePutUInt (Mp3ReadRegister(SPI_WRAM));
ConsolePutUInt (Mp3ReadRegister(SPI_WRAM));
ConsolePutChar(13);
#endif
Mp3SoftReset();
#if 1
ConsoleWrite("ClockF:");
ConsolePutUInt(Mp3ReadRegister(SPI_CLOCKF));
ConsolePutChar(13);
#endif
Mp3WriteRegister(SPI_WRAMADDR, 0xc0, 0x13);
ConsoleWrite("0xC013:");
ConsolePutUInt (Mp3ReadRegister(SPI_WRAM));
ConsolePutUInt (Mp3ReadRegister(SPI_WRAM));
ConsolePutChar(13);
/* Switch on the analog parts */
Mp3SetVolume(20,20);
SPISetFastClock();
ConsoleWrite ("Init: VS10XX\r");
}
/** VS10xx Sine Test Function - Good getting started example */
void VsSineTest(){
ConsoleWrite("Not For VS1053!"); /* Needs adjustment */
/* Reset MP3 chip */
Mp3PutInReset(); /* Pull xRESET low -> hardware reset */
Delay(100); /* 100 ms delay */
/* Send dummy SPI byte to initialize SPI of Atmel microcontroller */
SPIPutCharWithoutWaiting(0xFF);
/* Un-reset MP3 chip */
Mp3DeselectControl(); /* Pull xCS high */
Mp3DeselectData(); /* Pull xDCS high */
Mp3ReleaseFromReset(); /* Pull xRESET high */
Delay(100); /* 100 ms delay */
GREEN_LED = LED_ON;
RED_LED = LED_ON;
/* VS10xx Application Notes, chapter 4.8 ---------------------------------*/
/* As an example, let's write value 0x0820 to register 00 byte by byte */
Mp3SelectControl(); /* Now SPI writes go to SCI port */
SPIPutChar(0x02); /* Send SPI Byte, then wait for byte to be sent. */
SPIPutChar(0x00); /* 0x02 was WRITE command, 0x00 is register number */
SPIPutChar(0x08); /* This byte goes to MSB */
SPIPutChar(0x20); /* ..and this is LSB. (0x20=Allow Test Mode) */
SPIWait(); /* Wait until Atmel MCU signals SPI write complete */
Mp3DeselectControl(); /* Now SPI writes don't go to SCI port */
while (!MP3_DREQ) /* Wait for DREQ = 1 */
; /* Do nothing while waiting for DREQ = 1 */
/* Send a Sine Test Header to Data port */
Mp3SelectData(); /* Now SPI writes go to SDI port */
SPIPutChar(0x53); /* - This is a special VLSI Solution test header - */
SPIPutChar(0xef); /* - that starts a sine sound. It's good for - */
SPIPutChar(0x6e); /* - testing your code, the chip and also for - */
SPIPutChar(0x44); /* - seeing if your MP3 decoder was manufactured - */
SPIPutChar(0x00); /* - by VLSI Solution oy. ------------------------ */
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIWait();
Mp3DeselectData();
RED_LED = LED_OFF;
Delay (500); /* 500 ms delay */
GREEN_LED = LED_OFF;
/* Stop the sine test sound */
Mp3SelectData();
SPIPutChar(0x45);
SPIPutChar(0x78);
SPIPutChar(0x69);
SPIPutChar(0x74);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIWait();
Mp3DeselectData();
Delay(500); /* 500 ms delay */
}
/** Send 2048 zeros. */
void SendZerosToVS10xx(){
Mp3SelectData();
SPIPutCharWithoutWaiting(0);
for (temp.i=0; temp.i<1048; temp.i++){ /* TESTING 1048 TESTING */
while (!MP3_DREQ)
;
SPIPutChar(0);
}
SPIWait();
Mp3DeselectData();
}
//Link in experimental AVI file sound track playing
//#define AVIPLAY
//#ifdef AVIPLAY
//#include "aviplay.c"
//#endif
/** Send a number of disk sectors to vs10xx.
* Starting from current value in global variable sectorAddress,
* sends a number of disk sectors to vs10xx and returns. */
unsigned char PlayDiskSectors (unsigned int nSectorsToPlay){
/** How many sectors to send between ff/rew commands */
unsigned char fallbackCount = 0;
//#ifdef AVIPLAY
//if (!PlayAvi()) return 0; //try to play AVI file soundtrack starting from //current sector, if avifile is played, return.
//#endif
PrepareToReadDiskSector(sectorAddress.l);
while (nSectorsToPlay--){
AvailableProcessorTime();
ReadDiskSector(sectorAddress.l);
/* If playing state is something else than "play normally",
exit returning the request number. */
if ((playingState==PS_END_OF_SONG)||
(playingState==PS_NEXT_SONG)||
(playingState==PS_RECORDING)||
(playingState==PS_PREVIOUS_SONG)){
return playingState;
}
/* === REWIND / FAST FORWARD FUNCTIONALITY CODE BEGINS === */
/* If you don't implement rewind / fast forward, leave these lines out */
if (playingState==PS_FALLBACK_N){
if ((--fallbackCount)==0){
playingState=PS_NORMAL;
}
}
if (playingState==PS_FALLBACK_1){
/* Now we should have brand new sector in memory ready for sending to
VS1003, so let's send zeroes between old and new data. */
ConsoleWrite("(Zeros)");
SendZerosToVS10xx();
ConsoleWrite("->Fallback to normal");
fallbackCount = 24;
playingState = PS_FALLBACK_N;
}
if (playingState==PS_CUE){ //Request to start fast forward
if (Mp3ReadRegister(SPI_HDAT1)==((int)'W'<< 8)+'m'){
ConsoleWrite("\rWmCUE->Wait");
Mp3WriteRegister(SPI_AICTRL2, 0x12, 0x34);
playingState = PS_CUE_WAIT1003;
}else{
playingState = PS_CUE_ACTION;
}
}
if (playingState==PS_CUE_WAIT1003){ //Wait for permission to break data flow
if (Mp3ReadRegister(SPI_AICTRL2)==0x2345){ //permission granted
ConsoleWrite("->Action");
playingState = PS_CUE_ACTION;
}
}
if (playingState==PS_CUE_ACTION){
if (nSectorsToPlay>128){
sectorAddress.l += 128; //Skip sectors
nSectorsToPlay -= 128;
//adjust vs1003 song left
ConsoleWrite("->Fallback(5)");
playingState = PS_FALLBACK_1; //Sector already in memory still goes.
}
}
if (playingState==PS_REWIND){ //Request to start fast forward
Mp3WriteRegister(SPI_AICTRL2, 0x12, 0x34);
playingState = PS_REW_WAIT1003;
}
if (playingState==PS_REW_WAIT1003){ //Wait for permission to break data flow
if (1){
//if (Mp3ReadRegister(SPI_AICTRL2)==0x2345){ //permission granted
sectorAddress.l -= 128;
nSectorsToPlay += 128;
playingState = PS_FALLBACK_1; //Sector already in memory still goes.
//}
}
}
/* === END OF REWIND / FAST FORWARD FUNCTIONALITY CODE === */
sectorAddress.l++;
if (nSectorsToPlay){
/*Do not seek after the last sector*/
PrepareToReadDiskSector(sectorAddress.l);
}
Mp3SelectData();
dataBufPtr = diskSect.raw.buf;
while (dataBufPtr < diskSect.raw.buf+512){
if (!MP3_DREQ){
GREEN_LED = LED_ON;
while (!MP3_DREQ){
Mp3DeselectData();
AvailableProcessorTime();
Mp3SelectData();
}
}
GREEN_LED = LED_OFF;
/* Send 32 octets of disk block data to VS10xx */
//Mp3WriteRegister (SPI_MODE, 0x0C, 0x00); /* Newmode, No L1-2 */
SPIPutCharWithoutWaiting(*dataBufPtr++);
SPIWait();
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIPutChar(*dataBufPtr++);
SPIWait();
//Mp3WriteRegister (SPI_MODE, 0x08, 0x00); /* Newmode, No L1-2 */
}
SPIWait();
Mp3DeselectData();
}
return 0; //OK Exit
}
XxXxXxXxXxXxXxXxXxXxXxXx vs10xx.h XxXxXxXxXxXxXxXxXxXxXxXx
/** \file vs10xx.h
* Headers for interfacing with the mp3 player chip.
* Interfacing the New Way, not handling BSYNC -> not compatible with VS1001.
*/
#ifndef VS10XX_H
#define VS10XX_H
#include "board.h"
/** VS10xx SCI Write Command byte is 0x02 */
#define VS_WRITE_COMMAND 0x02
/** VS10xx SCI Read Command byte is 0x03 */
#define VS_READ_COMMAND 0x03
#define SPI_MODE 0x0 /**< VS10xx register */
#define SPI_STATUS 0x1 /**< VS10xx register */
#define SPI_BASS 0x2 /**< VS10xx register */
#define SPI_CLOCKF 0x3 /**< VS10xx register */
#define SPI_DECODE_TIME 0x4 /**< VS10xx register */
#define SPI_AUDATA 0x5 /**< VS10xx register */
#define SPI_WRAM 0x6 /**< VS10xx register */
#define SPI_WRAMADDR 0x7 /**< VS10xx register */
#define SPI_HDAT0 0x8 /**< VS10xx register */
#define SPI_HDAT1 0x9 /**< VS10xx register */
#define SPI_AIADDR 0xa /**< VS10xx register */
#define SPI_VOL 0xb /**< VS10xx register */
#define SPI_AICTRL0 0xc /**< VS10xx register */
#define SPI_AICTRL1 0xd /**< VS10xx register */
#define SPI_AICTRL2 0xe /**< VS10xx register */
#define SPI_AICTRL3 0xf /**< VS10xx register */
#define SM_DIFF 0x01 /**< VS10xx register */
#define SM_JUMP 0x02 /**< VS10xx register */
#define SM_RESET 0x04 /**< VS10xx register */
#define SM_OUTOFWAV 0x08 /**< VS10xx register */
#define SM_PDOWN 0x10 /**< VS10xx register */
#define SM_TESTS 0x20 /**< VS10xx register */
#define SM_STREAM 0x40 /**< VS10xx register */
#define SM_PLUSV 0x80 /**< VS10xx register */
#define SM_DACT 0x100 /**< VS10xx register */
#define SM_SDIORD 0x200 /**< VS10xx register */
#define SM_SDISHARE 0x400 /**< VS10xx register */
#define SM_SDINEW 0x800 /**< VS10xx register */
#define SM_ADPCM 0x1000 /**< VS10xx register */
#define SM_ADPCM_HP 0x2000 /**< VS10xx register */
/** Playing State Global, 0=normal playing, 1=abort playing */
extern xdata unsigned char playingState;
/** Execute VS1011/VS1002 Sine Test Function */
void VsSineTest();
void Mp3Reset();
/** Soft Reset of VS10xx (Between songs) */
void Mp3SoftReset();
/** Write VS10xx register*/
#define Mp3WriteRegister(addressbyte,highbyte,lowbyte){ \
Mp3SelectControl(); \
SPIPutCharWithoutWaiting(VS_WRITE_COMMAND); \
SPIPutChar((addressbyte)); \
SPIPutChar((highbyte)); \
SPIPutChar((lowbyte)); \
SPIWait(); \
Mp3DeselectControl(); \
}
/** Set VS10xx Volume Register */
#define Mp3SetVolume(leftchannel,rightchannel){\
Mp3WriteRegister(11,(leftchannel),(rightchannel));}
/** Read the 16-bit value of a VS10xx register */
unsigned int Mp3ReadRegister (unsigned char addressbyte);
/** Send 2048 zeros. \todo Timeouts for all DREQ busy loop waits! */
void SendZerosToVS10xx();
/** Play disk sectors from disk */
unsigned char PlayDiskSectors (unsigned int nSectorsToPlay);
/** This is called when there is free processor time, implement externally. */
void AvailableProcessorTime();
/** Soft reset without loading patch */
void Mp3SoftResetWithoutPatch();
/** Load User Patch */
void LoadUserPatch(void);
#endif
XxXxXxXxXxXxXxXxXxXxXxXx EOF XxXxXxXxXxXxXxXxXxXxXxXx
No comments:
Post a Comment