Embedded system Fun Blog
























































Find out all the best information, libraries and circuit about the latest Embedded systems.

Saturday, 7 January 2012

VS1011 MP3 Decoder Module: vs10xx.c and vs10xx.h

.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