Library for VS1053 chip with non blocking call to check dreq and cancel playback function

Dependents:   VS1053Player MP3_test MP3_final_S4P_ANDRIAMARO_RAKOTO_1

Fork of VS1053lib by clemente di caprio

VLSIcodec.cpp

Committer:
ollie8
Date:
2013-12-26
Revision:
4:ce980c240ae1
Parent:
3:59c27531f18e

File content as of revision 4:ce980c240ae1:

/** mbed VLSIcodec library. To access VS1053 MPEG3 codec.

    Copyright (c) 2010 NXP 3790 
 
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
 
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
 
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/
 
#include "mbed.h"
#include "VLSIcodec.h"
#include "VLSIcodec_patch.h"

#ifdef __ENCODE_OGG
#include "VLSIcodec_OGG.h"
#endif

#ifdef __PLUGINGA
#include "VLSIcodec_pluginGA.h"
#define cBASE   0x1800  /* Base address of X-RAM for a VS1053 */
#endif


//******************************************************************************
//******************************************************************************
// Section: Constants
//******************************************************************************
//******************************************************************************

#define VLSI_MODE           0x00
#define VLSI_STATUS         0x01
#define VLSI_BASS           0x02
#define VLSI_CLOCKF         0x03
#define VLSI_DECODE_TIME    0x04
#define VLSI_AUDATA         0x05
#define VLSI_WRAM           0x06
#define VLSI_WRAMADDR       0x07
#define VLSI_HDAT0          0x08
#define VLSI_HDAT1          0x09
#define VLSI_AIADDR         0x0A
#define VLSI_VOL            0x0B
#define VLSI_AICTRL0        0x0C
#define VLSI_AICTRL1        0x0D
#define VLSI_AICTRL2        0x0E
#define VLSI_AICTRL3        0x0F

#define VLSI_STATUS_VER     0x00F0u
#define VER_VS1001          (0u<<4)
#define VER_VS1011          (1u<<4)
#define VER_VS1002          (2u<<4)
#define VER_VS1011E         (2u<<4)
#define VER_VS1003          (3u<<4)
#define VER_VS1053          (4u<<4)
#define VER_VS1033          (5u<<4)
#define VER_VS1103          (7u<<4)

#define cWAIT_DREQ_1MS        wait_ms( 1); while (!_dreq);
#define cWAIT_DREQ            while (!_dreq);
                            
/* VLSI 1053, MODE Register bit configuration. */
#define SM_DIFF                0x01   
#define SM_LAYER12            0x02   
#define SM_RESET            0x04   
#define SM_CANCEL            0x08   
#define SM_EARSPEAKER_LO    0x10   
#define SM_TESTS            0x20   
#define SM_STREAM            0x40   
#define SM_EARSPEAKER_HI    0x80   
#define SM_DACT                0x100   
#define SM_SDIORD            0x200   
#define SM_SDISHARE            0x400   
#define SM_SDINEW            0x800   
#define SM_ADPCM            0x1000   
#define SM_NOTUSE            0x2000
#define SM_LINE1            0x4000
#define SM_CLK_RANGE        0x8000

/* SC MULT MASK CLKI */
#define SC_MULT_0         0x0000    /* XTALI */
#define SC_MULT_2         0x2000    /* XTALI×2.0 */
#define SC_MULT_2_5     0x4000    /* XTALI×2.5 */
#define SC_MULT_3         0x6000    /* XTALI×3.0 */
#define SC_MULT_3_5     0x8000    /* XTALI×3.5 */
#define SC_MULT_4         0xA000    /* XTALI×4.0 */
#define SC_MULT_4_5     0xC000    /* XTALI×4.5 */
#define SC_MULT_5         0xE000    /* XTALI×5.0 */

/* 
 SC ADD tells how much the decoder firmware is allowed to add to the multiplier specified by SC MULT
 if more cycles are temporarily needed to decode a WMA or AAC stream. The values are:
 SC ADD MASK Multiplier addition 
*/
#define SC_ADD_NOMOD    0x0000    /* No modification is allowed */
#define SC_ADD_X1         0x0800    /* 1.0× */
#define SC_ADD_X1_5     0x1000    /* 1.5× */
#define SC_ADD_X2        0x1800    /* 2.0× */

#define SC_FREQ            0x0000    /* 12.288 MHz clock. */

/*
*/
#define cMODEREG_SET    ( SM_SDINEW )
#define cCLOCK_SET        ( SC_MULT_5 | SC_ADD_X1 | SC_FREQ)

#define VS1053_CS_ENABLE        _cs=0;
#define VS1053_CS_DISABLE       _cs=1;
#define VS1053_XDCS_ENABLE      _xdcs=0;
#define VS1053_XDCS_DISABLE     _xdcs=1;
#define VS1053_RST_ENABLE       _rst=0;
#define VS1053_RST_DISABLE      _rst=1;

/*
*/
#define cVS1053_CS_DELAY        50

/** VS1053Codec
*/
VS1053Codec::VS1053Codec(  PinName mosi, PinName miso, PinName sclk, PinName cs, PinName dreq, PinName rst, PinName xdcs) : _spi( mosi, miso, sclk), _cs( cs), _dreq( dreq), _rst( rst), _xdcs( xdcs) {
    // defaults params
    VS1053_CS_DISABLE;
    VS1053_XDCS_DISABLE;
}

/** Wait untile the dreq is released
* @param none
* @retval none
*/
void VS1053Codec::testdreq( void){
    while( !_dreq);
}

bool VS1053Codec::checkdreq(void) {
    return _dreq;
}
   
/** Put the VS1053 in low power mode (RESET)
* 
* @param none
* @retval none
*/ 
void VS1053Codec::lowpower( void)
{
    VS1053_RST_ENABLE;
    wait_ms( 10);
}

/** Initialize the VS1053
*/
void VS1053Codec::init(void)
{
    //
    VS1053_RST_DISABLE;
    VS1053_CS_DISABLE;
    VS1053_XDCS_DISABLE;
    //
    _spi.format( 8, 0);
    _spi.frequency( MP3_INIT_SPEED);
    
    // Assert RESET
    VS1053_RST_ENABLE;
    wait_ms( 100);
    
    // Deassert RESET (active low)
    VS1053_RST_DISABLE;
    VS1053_CS_DISABLE;
    VS1053_XDCS_DISABLE;
    wait_ms( 100);
    
    // Wait 
    while(!_dreq);
    
    // Reset the vs1053
    writereg( VLSI_MODE, ( cMODEREG_SET | SM_RESET) );
    wait_ms( 10);
    
    // Wait...
    while(!_dreq); 

    /*
    * Write configuration MODE register in a loop to verify that the chip is
    * connected and running correctly
    */
    do
    {
        writereg( VLSI_MODE, ( cMODEREG_SET ));
        wait_ms( 1);
    }while( readreg( VLSI_MODE) != ( cMODEREG_SET ));

    //
    if((readreg( VLSI_STATUS) & VLSI_STATUS_VER) == VER_VS1053)
    {
        // Set the clock to maximum speed (VS1053 only) to allow all audio formats
        // to be decoded without glitching.  Note that this increases power
        // consumption.
        // SC_MULT = XTALI*4.5, SC_ADD = noMod, SC_FREQ = 0 (12.288MHz)
        // VLSIWriteReg(VLSI_CLOCKF, SC_MULT_4_5 | SC_ADD_X1 | SC_FREQ);
        
        writereg(VLSI_CLOCKF, cCLOCK_SET);
        
        /* */
        wait_ms( 2);
        while(!_dreq);
    }
    else if ((readreg( VLSI_STATUS) & VLSI_STATUS_VER) == VER_VS1011E)
    {
        // Nothing special to do
        ;
    }
    else
    {
        // VLSI Chip version not tested, not supported, halt program execution.
        // This trap should be caught during the design phase.
        while(1);
    }

    _spi.frequency( MP3_RUN_SPEED);
}

void VS1053Codec::loadpatch(void) 
/* Questa funzione carica una patch al firmware del codec */
{
    int i = 0, plgin_len;
    unsigned int addr, n, val;
    
    plgin_len=sizeof( plugin)/sizeof(plugin[0]);
    while (i<plgin_len) {

        addr = plugin[i++];
        n = plugin[i++];
        if (n & 0x8000U) { /* RLE run, replicate n samples */
            n &= 0x7FFF;
            val = plugin[i++];
            while (n--) {
                writeregnowait(addr, val); 
                while(!_dreq); 
            }
        } else {           /* Copy run, copy n samples */
            while (n--) {
                val = plugin[i++];
                writeregnowait(addr, val); 
                while(!_dreq);
            }
        }
    }
    //
    wait_ms( 1);
    while(!_dreq);
}

#ifdef __PLUGINGA
void VS1053Codec::loadgapatch(void) 
/* Questa funzione carica un plugin nel codec */
{
    int i = 0, plgin_len;
    unsigned int addr, n, val;
    
    plgin_len=sizeof( gaplugin)/sizeof(gaplugin[0]);
    while (i<plgin_len) {

        addr = gaplugin[i++];
        n = gaplugin[i++];
        if (n & 0x8000U) { /* RLE run, replicate n samples */
            n &= 0x7FFF;
            val = gaplugin[i++];
            while (n--) {
                writeregnowait(addr, val); 
                while(!_dreq); 
            }
        } else {           /* Copy run, copy n samples */
            while (n--) {
                val = gaplugin[i++];
                writeregnowait(addr, val); 
                while(!_dreq);
            }
        }
    }
    //
    wait_ms( 1);
    while(!_dreq);
}
#endif

#ifdef __ENCODE_OGG
void VS1053Codec::loadoggpatch(void) 
/* Questa funzione carica una patch per gestire l'encoder OGG */
{
    int i = 0, plgin_len;
    unsigned int addr, n, val;
    
    plgin_len=sizeof( ogg_enc)/sizeof(ogg_enc[0]);
    while (i<plgin_len) {

        addr = ogg_enc[i++];
        n = ogg_enc[i++];
        if (n & 0x8000U) { /* RLE run, replicate n samples */
            n &= 0x7FFF;
            val = ogg_enc[i++];
            while (n--) {
                writeregnowait(addr, val); 
                while(!_dreq); 
            }
        } else {           /* Copy run, copy n samples */
            while (n--) {
                val = ogg_enc[i++];
                writeregnowait(addr, val); 
                while(!_dreq);
            }
        }
    }
    //
    wait_ms( 1);
    while(!_dreq);
}
#endif

#ifdef __PLUGINGA    
void VS1053Codec::readgavalue( unsigned char *currval, unsigned char *peak)
{
    writereg( VLSI_WRAMADDR, cBASE+2);
    unsigned short bands = (unsigned short)readreg( VLSI_WRAM);
    //
    writereg( VLSI_WRAMADDR, cBASE+4);
    //
    for (int i=0;i<bands;i++) {
        short pv = readreg( VLSI_WRAM); 
        /* current value in bits 5..0, normally 0..31
        peak value in bits 11..6, normally 0..31 */
        currval[i]=(unsigned char)(pv&0x003F);
        peak[i]=(unsigned char)( (pv>>6)&0x003F);
    }
}

unsigned short VS1053Codec::readgabands( void)
{
    writereg( VLSI_WRAMADDR, cBASE+2);
    unsigned short bands = (unsigned short)readreg( VLSI_WRAM);
    /* */
    return bands;
}

#endif

void VS1053Codec::setvmeter( void)
{
    unsigned short tmp;
    
    tmp=(unsigned short)readreg( VLSI_STATUS);
    tmp|=(1<<9);
    writereg( VLSI_STATUS, tmp);
}

void VS1053Codec::getvmeterval( unsigned char* left, unsigned char* right)
{
    unsigned short tmp;
    
    tmp=(unsigned short)readreg( VLSI_AICTRL3);
    
    *right=(unsigned char)tmp&0x00FF;
    *left=(unsigned char)(tmp>>8);
}

/****************************************************************************
  Function:
    void VS1053Codec::setbassboost(BYTE bass, BYTE gfreq)

  Description:
    This function sets the bass boost.

  Precondition:
    None

  Parameters:
    BYTE bass   - Bass gain in dB, range from 0 to 15 (MSB nibble)
    BYTE gfreq  - Limit frequency for bass boost, 10 Hz steps (range from
                    20 to 150) (LSB nibble)

  Returns:
    None

  Remarks:
    None
  ***************************************************************************/
void VS1053Codec::setbassboost( unsigned char bass, unsigned char gfreq)
{
    unsigned char templ;
    unsigned short tmp;

    // 
    if(bass > 15u)
        bass = 15;
    if(gfreq > 150u)
        gfreq = 150;
    if ( gfreq < 20)
        gfreq = 20;
        

    // 
    templ = (unsigned char)gfreq/10;

    // put bass boost value into the upper 4 bit
    templ |= (bass << 4);
    //
    tmp=(unsigned short)readreg( VLSI_BASS);
    tmp &= 0xFF00;
    tmp |= templ;
    //
    writereg( VLSI_BASS, tmp);
}

/****************************************************************************
  Function:
    void VS1053Codec::settrebleboost(BYTE bass, WORD gfreq)

  Description:
    This function sets the bass boost.

  Precondition:
    None

  Parameters:
    BYTE treble   - Bass gain in dB, range from -8 to 7 (MSB nibble)
    WORD gfreq    - Limit frequency for bass boost, 1000 Hz steps (range from
                    1000 to 15000) (LSB nibble)

  Returns:
    None

  Remarks:
    None
  ***************************************************************************/
void VS1053Codec::settrebleboost( char treble, unsigned int gfreq)
{
    unsigned char templ;
    unsigned short tmp;

    // 
    if(treble > 7)
        treble = 7;
    if ( treble < (char)-8)
        treble = (char)-8;
        
    if(gfreq > 15000u)
        gfreq = 15000;
    if(gfreq < 1000)
        gfreq = 1000;

    // 
    templ = (unsigned char)gfreq/1000;

    // put treble boost value into the upper 4 bit
    templ |= (treble << 4);
    //
    tmp=(unsigned short)readreg( VLSI_BASS);
    tmp &= 0x00FF;
    tmp |= (templ << 8);
    //
    writereg( VLSI_BASS, tmp);
}

void VS1053Codec::getplaytime(char *playtime)
{
    unsigned short playTime;
    unsigned char minutes, seconds;
    
    playTime = (unsigned short)readreg(VLSI_DECODE_TIME);
    minutes = playTime/60;
    seconds = playTime%60;
    *playtime++=('0'+minutes/10);
    *playtime++=('0'+minutes%10);
    *playtime++=(':');
    *playtime++=('0'+seconds/10);
    *playtime++=('0'+seconds%10);
}

void VS1053Codec::resetplaytime() {
    writereg(VLSI_DECODE_TIME, 0);
    writereg(VLSI_DECODE_TIME, 0);
}

void VS1053Codec::cancelplayback() {
    unsigned int i = (unsigned short)readreg(VLSI_MODE);
    writereg( VLSI_MODE, ( i | SM_CANCEL ));
}

/****************************************************************************
  Function:
    void setvolume(unsigned char vRight, unsigned char vLeft)

  Description:
    This function set volume for analog outputs on the VLSI codec.

  Precondition:
    None

  Parameters:
    unsigned char vRight - right channel attenuation from maximum volume, 0.5dB steps
                        (0x00 = full volume, 0xFF = muted)
    unsigned char vLeft  - left channel attenuation from maximum volume, 0.5dB steps
                        (0x00 = full volume, 0xFF = muted)

  Returns:
    None

  Remarks:
    None
  ***************************************************************************/
void VS1053Codec::setvolume(unsigned char vRight, unsigned char vLeft)
{
    writereg(VLSI_VOL, ((unsigned int)vLeft)<<8 | vRight);
}


void VS1053Codec::sinetest( unsigned char pitch)
{
    unsigned int i;
    
    while(!_dreq);
    
    i=(unsigned short)readreg( VLSI_MODE);
    writereg( VLSI_MODE, ( i | SM_TESTS ));
    
    VS1053_XDCS_ENABLE;
    
    if ( pitch) {
        // START Sine Test
        _spi.write(0x53);
        _spi.write(0xEF);
        _spi.write(0x6E);
        _spi.write( pitch);
        _spi.write(0x00);
        _spi.write(0x00);
        _spi.write(0x00);
        _spi.write(0x00);
    } else {
        // STOP Sine Test
        _spi.write(0x45);
        _spi.write(0x78);
        _spi.write(0x69);
        _spi.write(0x74);
        _spi.write(0x00);
        _spi.write(0x00);
        _spi.write(0x00);
        _spi.write(0x00);
    }    
    
    VS1053_XDCS_DISABLE;

}

void VS1053Codec::writedata( unsigned char data)
/*
* Write data to SDI.
*/
{
    int i=0;
    
    VS1053_XDCS_ENABLE;
    for( i=0; i<cVS1053_CS_DELAY; i++);
    
    _spi.write( data);
    
    for( i=0; i<cVS1053_CS_DELAY; i++);
    VS1053_XDCS_DISABLE;
    
}
    
//******************************************************************************
//******************************************************************************
//******************************************************************************
// Section: Internal Functions
//******************************************************************************
//******************************************************************************
//******************************************************************************


unsigned short VS1053Codec::readreg(unsigned char vAddress)
{
    unsigned short wValue;
    unsigned int i;
    
    VS1053_CS_ENABLE;
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    
    _spi.write(0x03);     // Read
    _spi.write(vAddress); // Register address
    ((unsigned char*)&wValue)[1] = _spi.write(0xFF);   // 8 bit value high byte
    ((unsigned char*)&wValue)[0] = _spi.write(0xFF);   // 8 bit value low byte
    
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    VS1053_CS_DISABLE;

    return wValue;
}

void VS1053Codec::writereg(unsigned char vAddress, unsigned int wValue)
{
    int i;
    
    while(!_dreq);
    
    VS1053_CS_ENABLE;
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    
    _spi.write(0x02);     // Write
    _spi.write(vAddress); // Register address
    _spi.write(((unsigned char*)&wValue)[1]);      // 8 bit value to write high byte
    _spi.write(((unsigned char*)&wValue)[0]);      // 8 bit value to write low byte
    
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    VS1053_CS_DISABLE;
    
}


/* */
void VS1053Codec::reset( void)
{
    // Reset the vs1053
    writereg(VLSI_MODE, ( cMODEREG_SET | SM_RESET) );
    wait_ms( 5);
    // Wait...
    while(!_dreq);

    // Configure CLOCK register.
    writereg(VLSI_CLOCKF, cCLOCK_SET);
    wait_ms( 5);
    // Wait...
    while(!_dreq);
}
    

void VS1053Codec::writeregnowait(unsigned char vAddress, unsigned int wValue)
/*
 Write to SCI interface without waiting for the DREQ pin
*/
{
    int i;
    
    VS1053_CS_ENABLE;
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    
    _spi.write(0x02);     // Write
    _spi.write(vAddress); // Register address
    _spi.write(((unsigned char*)&wValue)[1]);      // 8 bit value to write high byte
    _spi.write(((unsigned char*)&wValue)[0]);      // 8 bit value to write low byte
    
    for ( i=0; i<cVS1053_CS_DELAY;i++);
    VS1053_CS_DISABLE;
    
}

#ifdef __ENCODE_OGG
void VS1053Codec::VoggEncoding_Start( void)
/* VorbisEncoder160c pag. 9 */
{
    unsigned short temp;
    
/* 2. vs1053b at 55.3MHz */
    writeregnowait( VLSI_CLOCKF, 0xC000);         cWAIT_DREQ_1MS;
/* 3. SCI_BASS to 0 */
    writeregnowait( VLSI_BASS, 0x0000);         cWAIT_DREQ_1MS;
/* 4. Disable user application (no wait fot DREQ pin and no delay, as from the VLSI source file example */
/*    record.c from playercode1053-Aug2009.zip                                                             */
    writeregnowait( VLSI_AIADDR, 0x0000); 
/* 5. Disable all IRQ except the SCI IRQ */
    writeregnowait( VLSI_WRAMADDR, 0xC01A);
    writeregnowait( VLSI_WRAM, 0x0002); 
/* 6. Load the plugin code... */
    loadoggpatch();
/* 7. Set bit SM_ADPCM to 1. */
    temp = (unsigned short)readreg( VLSI_MODE);                cWAIT_DREQ_1MS;
    temp |= SM_ADPCM;
    writeregnowait( VLSI_MODE, temp);             cWAIT_DREQ_1MS;
    writeregnowait( VLSI_AICTRL0, 0x0000);         cWAIT_DREQ_1MS;
/* 8. Set recording level. Value are for conservative AGC. */
    writeregnowait( VLSI_AICTRL1, 0x0000);         cWAIT_DREQ_1MS;
    writeregnowait( VLSI_AICTRL2, 4096);         cWAIT_DREQ_1MS;
/* 10. Set 0 to SCI_AICTRL3. */
    writeregnowait( VLSI_AICTRL3, 0x0000);         cWAIT_DREQ_1MS;
/* 11. Active the encoder... */
    wait_ms( 5);
    writeregnowait( VLSI_AIADDR, 0x0034); wait_ms( 1);
/* 12. wait DREQ high. */
    cWAIT_DREQ;                /* Loop forever. */

}

#if 0
void VS1053Codec::VoggEncoding_ReadStatus( RUNTIME_VOGG_VALUE *status)
/* VorbisEncoder160c par 2.3.4, pag. 11                 */
/* see VLSICodec.h for RUNTIME_VOGG_VALUE struct data.  */
{
    unsigned short temp, temph;
    
    /* Recording Time */
    writereg( VLSI_WRAMADDR, 0x0008); cWAIT_DREQ_1MS;
    temp = (unsigned short)readreg( VLSI_WRAM);                                /* LSB recording Time */
    temph= (unsigned short)readreg( VLSI_WRAM);                                /* MSB recording Time */
    status->rec_time = ((unsigned long)temph << 16) | temp;    

    /* Average bitrate */
    writereg( VLSI_WRAMADDR, 0x000C); cWAIT_DREQ_1MS;
    temp = (unsigned short)readreg( VLSI_WRAM);                                /* LSB Average bitrate */
    temph= (unsigned short)readreg( VLSI_WRAM);                                /* MSB Average bitrate */
    status->average_bitrate = ((unsigned long)temph << 16) | temp;    

    /* Sample Counter */
    writereg( VLSI_WRAMADDR, 0x1800); cWAIT_DREQ_1MS;
    temp = (unsigned short)readreg( VLSI_WRAM);                                /* LSB Sample Counter */
    temph= (unsigned short)readreg( VLSI_WRAM);                                /* MSB Average bitrate */
    status->sample_counter = ((unsigned long)temph << 16) | temp;
}
#endif
    
    
/*
* Questa funzione legge il registro SCI_HDAT1 per verificare la presenza di 
* sample disponibili. In caso ci siano li legge dal reg. SCI_HDAT0 
* salvandoli nel puntatore passatogli. Ritorna il numero di byte copiati.
*/
unsigned int VS1053Codec::VoggEncoding_ReadBuffer( unsigned char *voggSample)
/* VorbisEncoder160c pag. 10 */
{
    unsigned int  i;
    unsigned short temp, sample;
    
    temp=0;
    i=0;
    sample=0;

//    printf("readbuffer\r\n");
    
    do {
        /* reading the sample counter... */
        temp = (unsigned short)readreg( VLSI_HDAT1);
        if ( temp ) {
//            printf("sample %d\r\n", temp);
            /* there are samples... */
            i=0;
            while( i < temp) {
                /* read the sample as word */
                sample=(unsigned short)readreg( VLSI_HDAT0);
                /* save it into the array as single byte. */
                *voggSample++ = (unsigned char)(sample >> 8);                /* MSB */
                *voggSample++ = (unsigned char)(sample & 0x00FF);            /* LSB */
                i++;
                wait_ms( 1);
            }    
            
            /* Exit the loop. */
            break;
        } else {
//            printf("no sample\r\n");
            /* Exit the loop. */
            break;
        }    
    } while( 1);    
    /* just relax... */
    wait_ms( 1);
    /* Return the number of byte saved. */
    return i*2;
}
    
/* 
* Questa funzione esegue la procedura di fine encoding memorizzando i rimanenti sample
* nel puntatore passatogli. Ritorna il numero di sample letti.
*/
unsigned int VS1053Codec::VoggEncoding_Stop( unsigned char *voggSample)
/* VorbisEncoder160c pag. 11 */
{
    unsigned int res, i, ii;
    unsigned short temp, sample;
    res=0;
    temp=0;
    sample=0;
    
/* 1. set bit 0 to 1 */
    temp = (unsigned short)readreg( VLSI_AICTRL3);
    temp |= 0x0001;
    writereg( VLSI_AICTRL3, temp);
    
/* 2. continue reading data but checking the bit 1 of VLSI_AICTRL3 reg. */
    res=0;
    do {
        /* reading the sample counter... */
        temp = (unsigned short)readreg( VLSI_HDAT1);
        if ( temp) {
//            printf("EncStop: %d\r\n", temp);
            i=0;
            while( i < temp ) {
                /* */
                sample = (unsigned short)readreg( VLSI_HDAT0);
                *voggSample++ = (unsigned char)(sample >> 8);
                *voggSample++ = (unsigned char)sample & 0x00FF;
                i++;
                wait_ms( 1);
            }
            res+=i;
        }
        /* just relax... */
        wait_ms( 1);
        temp = (unsigned short)readreg( VLSI_AICTRL3);
        /* verify the bit 1 of VLSI_AICTRL3 reg. */
        if ( temp & 0x0002) {
//            printf("Encoding STOP\r\n");
            /* encoding has finished. */
            break;
        }    
    } while( 1);    /* Loop forever... */
/* 3. write the remaining word... */
    ii=0;
    do {
        temp = (unsigned short)readreg( VLSI_HDAT1);
        if ( temp) {
//            printf("Flush %d\r\n", temp);
            /* there are samples... */
            i=0;
            while( i < temp ) {            /* con il numero precedente. */
                /* */
                sample = (unsigned short)readreg( VLSI_HDAT0);
                *voggSample++ = (unsigned char)(sample >> 8);
                *voggSample++ = (unsigned char)sample & 0x00FF;                
                i++;
                wait_ms( 1);
            }    
            res+=i;
        } else {
            wait_ms( 1);
            ii++;
        }
    } while( ii<5);    /* Loops ... */
/* 4. read twise AICTRL3 */
    temp = (unsigned short)readreg( VLSI_AICTRL3);
    temp = (unsigned short)readreg( VLSI_AICTRL3);
//    printf("last read %d\r\n", temp);
    if ( temp & 0x0004 ) {
        /* remove last byte ( bits 7:0) from the last word. */
        voggSample--;
        *voggSample=0;
        res=(res*2)-1;
    } else {
        res=res*2;
    }
/* 5. Reset the codec. */

    /* Ritorno il numero di sample, in byte, letti. */
    return res;    
}    
#endif