Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

vs1001.cpp

Go to the documentation of this file.
00001 /*  VLSI Logic VS1001 MPEG Decoder
00002 
00003     14.09.2001: tk, the DMA is now disabled during SCI accesses.
00004                     (see datasheet: After using the Serial Command
00005                      Interface, it is not allowed to send SCI or SDI
00006                      data for 5 microseconds)
00007     30.08.2001: tk, small changes for final VS1001k revision.
00008                     - GetBitrate() removed.
00009                     - GetSamplerate() removed.
00010                     These functions can be simulated by parsing
00011                     the mp3 header anyways.
00012     15.06.2001: tk, initial implementation.
00013 
00014     Copyright (c)2000 by Thomas Kindler, thomas.kindler@gmx.de
00015 
00016     This program is free software; you can redistribute it and/or
00017     modify it under the terms of the GNU General Public License as
00018     published by the Free Software Foundation; either version 2 of
00019     the License, or (at your option) any later version. Read the
00020     full License at http://www.gnu.org/copyleft for more details.
00021 */
00022 
00023 // include files -----
00024 //
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include "amd186.h"
00028 #include "clib/hwapi.h"
00029 #include "clib/rtos.h"
00030 #include "misc.h"
00031 #include "vs1001.h"
00032 
00033 // Some VS1001 settings, so we can restore
00034 // them after a reset.
00035 //
00036 static int  lastVolLeft, lastVolRight;
00037 static long lastFrequency;
00038 static bool lastBassBoost;
00039 
00040 // old DMA terminal count handler
00041 //
00042 static void interrupt (*oldDmaHandler)(...);
00043 
00044 // user defined callback function
00045 //
00046 static void (*callbackFunction)(void *);
00047 static void  *callbackParam;
00048 
00049 
00050 static void SCI_Write(unsigned data)
00051 {
00052   for (int i=15; i>=0; i--) {
00053     if (data & 1<<i)
00054       AMD_PioHigh(AMD_PIOPIN[SCI_SIPIO]);
00055     else
00056       AMD_PioLow(AMD_PIOPIN[SCI_SIPIO]);
00057     AMD_PioHigh(AMD_PIOPIN[SCI_SCLKPIO]);
00058     AMD_PioLow(AMD_PIOPIN[SCI_SCLKPIO]);
00059   }
00060 }
00061 
00062 
00063 static unsigned SCI_Read()
00064 {
00065   unsigned data = 0;
00066   for (int i=15; i>=0; i--) {
00067     AMD_PioHigh(AMD_PIOPIN[SCI_SCLKPIO]);
00068     if (AMD_GetPio(AMD_PIOPIN[SCI_SOPIO]))
00069       data |= 1<<i;
00070     AMD_PioLow(AMD_PIOPIN[SCI_SCLKPIO]);
00071   }
00072   return data;
00073 }
00074 
00075 
00076 static unsigned SCI_ReadReg(int address)
00077 {
00078   AMD_EnableDrq(SDI_DMACHANNEL, 0);
00079   AMD_PioLow(AMD_PIOPIN[SCI_SCLKPIO]);
00080   AMD_PioLow(AMD_PIOPIN[SCI_XCSPIO]);
00081   SCI_Write( 0x0300 | address );
00082   unsigned data = SCI_Read();
00083   AMD_PioHigh(AMD_PIOPIN[SCI_XCSPIO]);
00084   usleep(5);
00085   AMD_EnableDrq(SDI_DMACHANNEL, 1);
00086   return data;
00087 }
00088 
00089 
00090 static void SCI_WriteReg(int address, unsigned data)
00091 {
00092   AMD_EnableDrq(SDI_DMACHANNEL, 0);
00093   AMD_PioLow(AMD_PIOPIN[SCI_SCLKPIO]);
00094   AMD_PioLow(AMD_PIOPIN[SCI_XCSPIO]);
00095   SCI_Write( 0x0200 | address );
00096   SCI_Write( data );
00097   AMD_PioHigh(AMD_PIOPIN[SCI_XCSPIO]);
00098   usleep(5);
00099   AMD_EnableDrq(SDI_DMACHANNEL, 1);
00100 }
00101 
00102 
00109 static void interrupt DmaHandler(...)
00110 {
00111   if (callbackFunction)
00112     callbackFunction(callbackParam);
00113   oldDmaHandler();
00114 }
00115 
00116 
00122 bool VS_IsPlaying()
00123 {
00124   DmaInfo  dma;
00125 
00126   // check DMA status
00127   //
00128   AMD_GetDmaInfo(SDI_DMACHANNEL, &dma);
00129   return dma.control & DCON_ST ? true : false;
00130 }
00131 
00132 
00149 void VS_PlayMpegAsync( char *data, unsigned len,
00150                        void (*function)(void *),
00151                        void  *param )
00152 {
00153   // set up DMA channel
00154   //
00155   DmaInfo  dma;
00156   dma.control = DCON_DSYNC | DCON_SMIO | DCON_SINC | DCON_TC | DCON_INT;
00157   dma.length  = len;
00158   dma.srcMem  = data;
00159   dma.dstPort = SDI_DATAREG;
00160 
00161   callbackFunction = function;
00162   callbackParam    = param;
00163 
00164   // enable DMA request pin
00165   //
00166   AMD_StartDma(SDI_DMACHANNEL, &dma);
00167   AMD_EnableDrq(SDI_DMACHANNEL, true);
00168 }
00169 
00170 
00184 int VS_PlayMpegSync(char *data, unsigned len)
00185 {
00186   VS_PlayMpegAsync(data, len, NULL, 0);
00187   while (VS_IsPlaying());
00188 
00189   return VS_OK;
00190 }
00191 
00192 
00200 void SDI_WriteZeros(unsigned length)
00201 {
00202   char zeros[256] = {0};
00203   int  block;
00204 
00205   while (length > 0) {
00206     block = min(length, sizeof(zeros));
00207     VS_PlayMpegSync(zeros, block);
00208     length -= block;;
00209   }
00210 }
00211 
00212 
00217 void VS_Stop()
00218 {
00219   // stop DMA channel
00220   AMD_StopDma(SDI_DMACHANNEL);
00221 }
00222 
00223 
00234 void VS_SetVolume(int left, int right)
00235 {
00236   lastVolLeft = left;
00237   lastVolRight = right;
00238   SCI_WriteReg(SCI_VOL, ((255-left)<<8) | (255-right));
00239 }
00240 
00241 
00250 void VS_GetMPEGHeader(unsigned long *header)
00251 {
00252   ((unsigned *)header)[0] = SCI_ReadReg(SCI_HDAT0);
00253   ((unsigned *)header)[1] = SCI_ReadReg(SCI_HDAT1);
00254 }
00255 
00256 
00269 void VS_SetClockFreq(long frequency)
00270 {
00271   lastFrequency = frequency;
00272   if (frequency < 18432000)
00273     SCI_WriteReg(SCI_CLOCKF, (frequency/2000) | 0x8000);
00274   else
00275     SCI_WriteReg(SCI_CLOCKF, (frequency/2000));
00276 }
00277 
00278 
00284 void VS_SetBassBoost(bool onoff)
00285 {
00286   lastBassBoost = onoff;
00287   if (onoff)
00288     SCI_WriteReg(SCI_MODE, SCI_ReadReg(SCI_MODE) | SM_BASS);
00289   else
00290     SCI_WriteReg(SCI_MODE, SCI_ReadReg(SCI_MODE) & ~SM_BASS);
00291 }
00292 
00293 
00299 void VS_SDITest()
00300 {
00301   char beepOn[] = { 0x53, 0xef, 0x6e, 0x3e, 0, 0, 0, 0 };
00302   char beepOff[]= { 0x45, 0x78, 0x69, 0x74, 0, 0, 0, 0 };
00303 
00304   printf("Testing SDI interface");
00305   for (int i=0; i<25; i++) {
00306     VS_PlayMpegSync(beepOn, sizeof(beepOn));
00307     RTX_Sleep_Time(100);
00308     VS_PlayMpegSync(beepOff, sizeof(beepOff));
00309     RTX_Sleep_Time(100);
00310     printf(".");
00311   }
00312   printf(" ok.\n");
00313 }
00314 
00315 
00320 void VS_SCITest()
00321 {
00322   printf("Testing SCI interface");
00323   for (int i=0; i<25; i++) {
00324     VS_SetVolume(0, 0);
00325     RTX_Sleep_Time(100);
00326     VS_SetVolume(255,255);
00327     RTX_Sleep_Time(100);
00328     printf(".");
00329   }
00330   printf(" ok.\n");
00331 }
00332 
00333 
00338 void VS_Dump()
00339 {
00340   printf("VS1001 SCI registers ---\n");
00341   printf("  MODE    = %04x\n", SCI_ReadReg(SCI_MODE));
00342   printf("  STATUS  = %04x\n", SCI_ReadReg(SCI_STATUS));
00343   printf("  CLOCKF  = %04x\n", SCI_ReadReg(SCI_CLOCKF));
00344   printf("  DECTIME = %04x\n", SCI_ReadReg(SCI_DECTIME));
00345   printf("  AUDATA  = %04x\n", SCI_ReadReg(SCI_AUDATA));
00346   printf("  HDAT0   = %04x\n", SCI_ReadReg(SCI_HDAT0));
00347   printf("  HDAT1   = %04x\n", SCI_ReadReg(SCI_HDAT1));
00348   printf("  A1ADDR  = %04x\n", SCI_ReadReg(SCI_A1ADDR));
00349   printf("  VOL     = %04x\n", SCI_ReadReg(SCI_VOL));
00350   printf("  A1CTRL0 = %04x\n", SCI_ReadReg(SCI_A1CTRL0));
00351   printf("  A1CTRL1 = %04x\n", SCI_ReadReg(SCI_A1CTRL1));
00352   printf("  A1CTRL2 = %04x\n", SCI_ReadReg(SCI_A1CTRL2));
00353 }
00354 
00355 
00362 void VS_Reset()
00363 {
00364   AMD_EnableDrq(SDI_DMACHANNEL, 0);
00365   SCI_WriteReg(SCI_MODE, SM_RESET);
00366   usleep(500);
00367   if (SCI_ReadReg(SCI_MODE) == SM_RESET)
00368     printf( "OMFG: VS1001 Software reset failed.\n"
00369             "  Why don't they implement a watchdog timer,\n"
00370             "  or a reset bit that *works*?! Go and write\n"
00371             "  some mail to info@vlsi.fi :)\n"
00372           );
00373   VS_SetClockFreq(lastFrequency);
00374   VS_SetVolume(lastVolLeft, lastVolRight);
00375   VS_SetBassBoost(lastBassBoost);
00376   SDI_WriteZeros(2);
00377 }
00378 
00379 
00384 void VS_Init()
00385 {
00386   printf("SCI_Init(): initializing VS1001..\n");
00387 
00388   // enable SCI PIOs
00389   //
00390   pfe_enable_bus(0xff, true);
00391   pfe_enable_pcs(SDI_DATAREG >> 8);
00392 
00393   pfe_enable_pio(SCI_XCSPIO,  PIO_O1  );
00394   pfe_enable_pio(SCI_SCLKPIO, PIO_O0  );
00395   pfe_enable_pio(SCI_SIPIO,   PIO_O0  );
00396   pfe_enable_pio(SCI_SOPIO,   PIO_IPU );
00397 
00398   // install DMA terminal count interrupt
00399   //
00400   oldDmaHandler = getvect(10);
00401   setvect(10, DmaHandler);
00402 
00403   // initialize settings, and reset the VS1001
00404   //
00405   lastVolLeft   = 255;
00406   lastVolRight  = 255;
00407   lastFrequency = VS_CLOCK;
00408   lastBassBoost = true;
00409   VS_Reset();
00410 }
00411 
00412 
00417 void VS_Done()
00418 {
00419   // disable DMA channel
00420   //
00421   VS_Stop();
00422 
00423   if (oldDmaHandler)
00424     setvect(10, oldDmaHandler);
00425 }

Generated on Sun Aug 4 21:47:28 2002 for k/os mp3v2 by doxygen1.2.16