00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00034
00035
00036 static int lastVolLeft, lastVolRight;
00037 static long lastFrequency;
00038 static bool lastBassBoost;
00039
00040
00041
00042 static void interrupt (*oldDmaHandler)(...);
00043
00044
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
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
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
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
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
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
00399
00400 oldDmaHandler = getvect(10);
00401 setvect(10, DmaHandler);
00402
00403
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
00420
00421 VS_Stop();
00422
00423 if (oldDmaHandler)
00424 setvect(10, oldDmaHandler);
00425 }