| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- /*
- * Copyright (C) 2003 by Pavel Chromy. All rights reserved.
- * Copyright (C) 2001-2006 by egnite Software GmbH. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- * -
- *
- * This software has been inspired by all the valuable work done by
- * Jesper Hansen <jesperh@telia.com>. Many thanks for all his help.
- */
- /*!
- * \file arch/avr/dev/vs1001k.c
- * \brief Legacy support for VS1001K.
- *
- * \verbatim
- * $Id: vs1001k.c 4937 2013-01-22 11:38:42Z haraldkipp $
- * \endverbatim
- */
- /*
- * This header file specifies the hardware port bits. You
- * need to change or replace it, if your hardware differs.
- */
- #include <cfg/arch/avr.h>
- #include <sys/atom.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/heap.h>
- #include <dev/irqreg.h>
- #include <dev/vs1001k.h>
- #include <sys/bankmem.h>
- #include <stddef.h> /* NULL definition */
- /*!
- * \addtogroup xgVs1001
- */
- /*@{*/
- #ifndef VS_SCK_BIT
- /*!
- * \brief VS1001 serial control interface clock input bit.
- *
- * The first rising clock edge after XCS has gone low marks the first
- * bit to be written to the decoder.
- */
- #define VS_SCK_BIT 0
- #endif
- #if !defined(VS_SCK_AVRPORT) || (VS_SCK_AVRPORT == AVRPORTB)
- #define VS_SCK_PORT PORTB /*!< Port register of \ref VS_SCK_BIT. */
- #define VS_SCK_DDR DDRB /*!< Data direction register of \ref VS_SCK_BIT. */
- #elif (VS_SCK_AVRPORT == AVRPORTD)
- #define VS_SCK_PORT PORTD
- #define VS_SCK_DDR DDRD
- #elif (VS_SCK_AVRPORT == AVRPORTE)
- #define VS_SCK_PORT PORTE
- #define VS_SCK_DDR DDRE
- #elif (VS_SCK_AVRPORT == AVRPORTF)
- #define VS_SCK_PORT PORTF
- #define VS_SCK_DDR DDRF
- #else
- #warning "Bad SCK port specification"
- #endif
- #ifndef VS_SS_BIT
- /*!
- * \brief VS1001 serial data interface clock input bit.
- */
- #define VS_SS_BIT 1
- #endif
- #if !defined(VS_SS_AVRPORT) || (VS_SS_AVRPORT == AVRPORTB)
- #define VS_SS_PORT PORTB /*!< Port output register of \ref VS_SS_BIT. */
- #define VS_SS_DDR DDRB /*!< Data direction register of \ref VS_SS_BIT. */
- #elif (VS_SS_AVRPORT == AVRPORTD)
- #define VS_SS_PORT PORTD
- #define VS_SS_DDR DDRD
- #elif (VS_SS_AVRPORT == AVRPORTE)
- #define VS_SS_PORT PORTE
- #define VS_SS_DDR DDRE
- #elif (VS_SS_AVRPORT == AVRPORTF)
- #define VS_SS_PORT PORTF
- #define VS_SS_DDR DDRF
- #else
- #warning "Bad SS port specification"
- #endif
- #ifndef VS_SI_BIT
- /*!
- * \brief VS1001 serial control interface data input.
- *
- * The decoder samples this input on the rising edge of SCK if XCS is low.
- */
- #define VS_SI_BIT 2
- #endif
- #if !defined(VS_SI_AVRPORT) || (VS_SI_AVRPORT == AVRPORTB)
- #define VS_SI_PORT PORTB /*!< Port output register of \ref VS_SI_BIT. */
- #define VS_SI_DDR DDRB /*!< Data direction register of \ref VS_SI_BIT. */
- #elif (VS_SI_AVRPORT == AVRPORTD)
- #define VS_SI_PORT PORTD
- #define VS_SI_DDR DDRD
- #elif (VS_SI_AVRPORT == AVRPORTE)
- #define VS_SI_PORT PORTE
- #define VS_SI_DDR DDRE
- #elif (VS_SI_AVRPORT == AVRPORTF)
- #define VS_SI_PORT PORTF
- #define VS_SI_DDR DDRF
- #else
- #warning "Bad SI port specification"
- #endif
- #ifndef VS_SO_BIT
- /*!
- * \brief VS1001 serial control interface data output.
- *
- * If data is transfered from the decoder, bits are shifted out on the
- * falling SCK edge. If data is transfered to the decoder, SO is at a
- * high impedance state.
- */
- #define VS_SO_BIT 3
- #endif
- #if !defined(VS_SO_AVRPORT) || (VS_SO_AVRPORT == AVRPORTB)
- #define VS_SO_PIN PINB /*!< Port input register of \ref VS_SO_BIT. */
- #define VS_SO_DDR DDRB /*!< Data direction register of \ref VS_SO_BIT. */
- #elif (VS_SO_AVRPORT == AVRPORTD)
- #define VS_SO_PIN PIND
- #define VS_SO_DDR DDRD
- #elif (VS_SO_AVRPORT == AVRPORTE)
- #define VS_SO_PIN PINE
- #define VS_SO_DDR DDRE
- #elif (VS_SO_AVRPORT == AVRPORTF)
- #define VS_SO_PIN PINF
- #define VS_SO_DDR DDRF
- #else
- #warning "Bad SO port specification"
- #endif
- #ifndef VS_XCS_BIT
- /*!
- * \brief VS1001 active low chip select input.
- *
- * A high level forces the serial interface into standby mode, ending
- * the current operation. A high level also forces serial output (SO)
- * to high impedance state.
- */
- #define VS_XCS_BIT 4
- #endif
- #if !defined(VS_XCS_AVRPORT) || (VS_XCS_AVRPORT == AVRPORTB)
- #define VS_XCS_PORT PORTB /*!< Port output register of \ref VS_XCS_BIT. */
- #define VS_XCS_DDR DDRB /*!< Data direction register of \ref VS_XCS_BIT. */
- #elif (VS_XCS_AVRPORT == AVRPORTD)
- #define VS_XCS_PORT PORTD
- #define VS_XCS_DDR DDRD
- #elif (VS_XCS_AVRPORT == AVRPORTE)
- #define VS_XCS_PORT PORTE
- #define VS_XCS_DDR DDRE
- #elif (VS_XCS_AVRPORT == AVRPORTF)
- #define VS_XCS_PORT PORTF
- #define VS_XCS_DDR DDRF
- #else
- #warning "Bad XCS port specification"
- #endif
- #ifndef VS_BSYNC_BIT
- /*!
- * \brief VS1001 serial data interface bit sync.
- *
- * The first DCLK sampling edge, during which BSYNC is high, marks the
- * first bit of a data byte.
- */
- #define VS_BSYNC_BIT 5
- #endif
- #if !defined(VS_BSYNC_AVRPORT) || (VS_BSYNC_AVRPORT == AVRPORTB)
- #define VS_BSYNC_PORT PORTB /*!< Port output register of \ref VS_BSYNC_BIT. */
- #define VS_BSYNC_DDR DDRB /*!< Data direction register of \ref VS_BSYNC_BIT. */
- #elif (VS_BSYNC_AVRPORT == AVRPORTD)
- #define VS_BSYNC_PORT PORTD
- #define VS_BSYNC_DDR DDRD
- #elif (VS_BSYNC_AVRPORT == AVRPORTE)
- #define VS_BSYNC_PORT PORTE
- #define VS_BSYNC_DDR DDRE
- #elif (VS_BSYNC_AVRPORT == AVRPORTF)
- #define VS_BSYNC_PORT PORTF
- #define VS_BSYNC_DDR DDRF
- #else
- #warning "Bad BSYNC port specification"
- #endif
- #ifndef VS_RESET_BIT
- /*!
- * \brief VS1001 hardware reset input.
- */
- #define VS_RESET_BIT 7
- #endif
- #if !defined(VS_RESET_AVRPORT) || (VS_RESET_AVRPORT == AVRPORTB)
- #define VS_RESET_PORT PORTB /*!< Port output register of \ref VS_RESET_BIT. */
- #define VS_RESET_DDR DDRB /*!< Data direction register of \ref VS_RESET_BIT. */
- #elif (VS_RESET_AVRPORT == AVRPORTD)
- #define VS_RESET_PORT PORTD
- #define VS_RESET_DDR DDRD
- #elif (VS_RESET_AVRPORT == AVRPORTE)
- #define VS_RESET_PORT PORTE
- #define VS_RESET_DDR DDRE
- #elif (VS_RESET_AVRPORT == AVRPORTF)
- #define VS_RESET_PORT PORTF
- #define VS_RESET_DDR DDRF
- #else
- #warning "Bad RESET port specification"
- #endif
- #ifndef VS_SIGNAL_IRQ
- /*!
- * \brief VS1001 data request interrupt.
- */
- #define VS_SIGNAL sig_INTERRUPT6
- #define VS_DREQ_BIT 6
- #define VS_DREQ_PORT PORTE /*!< Port output register of \ref VS_DREQ_BIT. */
- #define VS_DREQ_PIN PINE /*!< Port input register of \ref VS_DREQ_BIT. */
- #define VS_DREQ_DDR DDRE /*!< Data direction register of \ref VS_DREQ_BIT. */
- #elif (VS_SIGNAL_IRQ == INT0)
- #define VS_SIGNAL sig_INTERRUPT0
- #define VS_DREQ_BIT 0
- #define VS_DREQ_PORT PORTD
- #define VS_DREQ_PIN PIND
- #define VS_DREQ_DDR DDRD
- #elif (VS_SIGNAL_IRQ == INT1)
- #define VS_SIGNAL sig_INTERRUPT1
- #define VS_DREQ_BIT 1
- #define VS_DREQ_PORT PORTD
- #define VS_DREQ_PIN PIND
- #define VS_DREQ_DDR DDRD
- #elif (VS_SIGNAL_IRQ == INT2)
- #define VS_SIGNAL sig_INTERRUPT2
- #define VS_DREQ_BIT 2
- #define VS_DREQ_PORT PORTD
- #define VS_DREQ_PIN PIND
- #define VS_DREQ_DDR DDRD
- #elif (VS_SIGNAL_IRQ == INT3)
- #define VS_SIGNAL sig_INTERRUPT3
- #define VS_DREQ_BIT 3
- #define VS_DREQ_PORT PORTD
- #define VS_DREQ_PIN PIND
- #define VS_DREQ_DDR DDRD
- #elif (VS_SIGNAL_IRQ == INT4)
- #define VS_SIGNAL sig_INTERRUPT4
- #define VS_DREQ_BIT 4
- #define VS_DREQ_PORT PORTE
- #define VS_DREQ_PIN PINE
- #define VS_DREQ_DDR DDRE
- #elif (VS_SIGNAL_IRQ == INT5)
- #define VS_SIGNAL sig_INTERRUPT5
- #define VS_DREQ_BIT 5
- #define VS_DREQ_PORT PORTE
- #define VS_DREQ_PIN PINE
- #define VS_DREQ_DDR DDRE
- #elif (VS_SIGNAL_IRQ == INT7)
- #define VS_SIGNAL sig_INTERRUPT7
- #define VS_DREQ_BIT 7
- #define VS_DREQ_PORT PORTE
- #define VS_DREQ_PIN PINE
- #define VS_DREQ_DDR DDRE
- #else
- #warning "Bad interrupt specification"
- #endif
- static volatile uint8_t vs_status = VS_STATUS_STOPPED;
- static volatile uint16_t vs_flush;
- /*
- * \brief Write a byte to the VS1001 data interface.
- *
- * The caller is responsible for checking the DREQ line. Also make sure,
- * that decoder interrupts are disabled.
- *
- * \param b Byte to be shifted to the decoder's data interface.
- */
- static INLINE void VsSdiPutByte(uint8_t b)
- {
- #ifdef VS_NOSPI
- uint8_t mask = 0x80;
- sbi(VS_BSYNC_PORT, VS_BSYNC_BIT);
- while (mask) {
- if (b & mask)
- sbi(VS_SI_PORT, VS_SI_BIT);
- else
- cbi(VS_SI_PORT, VS_SI_BIT);
- sbi(VS_SS_PORT, VS_SS_BIT);
- mask >>= 1;
- cbi(VS_SS_PORT, VS_SS_BIT);
- cbi(VS_BSYNC_PORT, VS_BSYNC_BIT);
- }
- #else
- /* Wait for previous SPI transfer to finish. */
- loop_until_bit_is_set(SPSR, SPIF);
- sbi(VS_BSYNC_PORT, VS_BSYNC_BIT);
- outb(SPDR, b);
- _NOP();
- _NOP();
- _NOP();
- _NOP();
- cbi(VS_BSYNC_PORT, VS_BSYNC_BIT);
- #endif
- }
- /*!
- * \brief Write a specified number of bytes to the VS1001 data interface.
- *
- * This function will check the DREQ line. Decoder interrupts must have
- * been disabled before calling this function.
- */
- static int VsSdiWrite(const uint8_t * data, uint16_t len)
- {
- uint16_t try = 5000;
- while (len--) {
- while (try-- && bit_is_clear(VS_DREQ_PIN, VS_DREQ_BIT));
- VsSdiPutByte(*data);
- data++;
- }
- return try ? 0 : -1;
- }
- /*!
- * \brief Write a specified number of bytes from program space to the
- * VS1001 data interface.
- *
- * This function is similar to VsSdiWrite() except that the data is
- * located in program space.
- */
- static int VsSdiWrite_P(PGM_P data, uint16_t len)
- {
- uint16_t try = 5000;
- while (len--) {
- while (try-- && bit_is_clear(VS_DREQ_PIN, VS_DREQ_BIT));
- VsSdiPutByte(PRG_RDB(data));
- data++;
- }
- return try ? 0 : -1;
- }
- /*!
- * \brief Write a byte to the serial control interface.
- *
- * Decoder interrupts must have been disabled and the decoder chip
- * select must have been enabled before calling this function.
- */
- static INLINE void VsSciPutByte(uint8_t data)
- {
- uint8_t mask = 0x80;
- /*
- * Loop until all 8 bits are processed.
- */
- while (mask) {
- /* Set data line. */
- if (data & mask)
- sbi(VS_SI_PORT, VS_SI_BIT);
- else
- cbi(VS_SI_PORT, VS_SI_BIT);
- /* Toggle clock and shift mask. */
- sbi(VS_SCK_PORT, VS_SCK_BIT);
- mask >>= 1;
- cbi(VS_SCK_PORT, VS_SCK_BIT);
- }
- }
- /*!
- * \brief Read a byte from the serial control interface.
- *
- * Decoder interrupts must have been disabled and the decoder chip
- * select must have been enabled before calling this function.
- */
- static INLINE uint8_t VsSciGetByte(void)
- {
- uint8_t mask = 0x80;
- uint8_t data = 0;
- /*
- * Loop until all 8 bits are processed.
- */
- while (mask) {
- /* Toggle clock and get the data. */
- sbi(VS_SCK_PORT, VS_SCK_BIT);
- if (bit_is_set(VS_SO_PIN, VS_SO_BIT))
- data |= mask;
- mask >>= 1;
- cbi(VS_SCK_PORT, VS_SCK_BIT);
- }
- return data;
- }
- /*!
- * \brief Write to a decoder register.
- *
- * Decoder interrupts must have been disabled before calling this function.
- */
- static void VsRegWrite(uint8_t reg, uint16_t data)
- {
- /* Select chip. */
- cbi(VS_XCS_PORT, VS_XCS_BIT);
- #ifndef VS_NOSPI
- /* Disable SPI */
- cbi(SPCR, SPE);
- #endif
- VsSciPutByte(VS_OPCODE_WRITE);
- VsSciPutByte(reg);
- VsSciPutByte((uint8_t) (data >> 8));
- VsSciPutByte((uint8_t) data);
- #ifndef VS_NOSPI
- /* Re-enable SPI. Hint given by Jesper Hansen. */
- outb(SPCR, BV(MSTR) | BV(SPE));
- outb(SPSR, inb(SPSR));
- #endif
- /* Deselect chip. */
- sbi(VS_XCS_PORT, VS_XCS_BIT);
- }
- /*
- * \brief Read from a register.
- *
- * Decoder interrupts must have been disabled before calling this function.
- *
- * \return Register contents.
- */
- static uint16_t VsRegRead(uint8_t reg)
- {
- uint16_t data;
- /* Disable interrupts and select chip. */
- cbi(VS_XCS_PORT, VS_XCS_BIT);
- #ifndef VS_NOSPI
- /* Disable SPI. */
- cbi(SPCR, SPE);
- #endif
- VsSciPutByte(VS_OPCODE_READ);
- VsSciPutByte(reg);
- data = (uint16_t)VsSciGetByte() << 8;
- data |= VsSciGetByte();
- #ifndef VS_NOSPI
- /* Re-enable SPI. Changed due to a hint by Jesper. */
- outb(SPCR, BV(MSTR) | BV(SPE));
- outb(SPSR, inb(SPSR));
- #endif
- /* Deselect chip and enable interrupts. */
- sbi(VS_XCS_PORT, VS_XCS_BIT);
- return data;
- }
- /*!
- * \brief Enable or disable player interrupts.
- *
- * This routine is typically used by applications when dealing with
- * unprotected buffers.
- *
- * \param enable Disables interrupts when zero. Otherwise interrupts
- * are enabled.
- *
- * \return Zero if interrupts were disabled before this call.
- */
- uint8_t VsPlayerInterrupts(uint8_t enable)
- {
- static uint8_t is_enabled = 0;
- uint8_t rc;
- rc = is_enabled;
- if(enable) {
- NutIrqEnable(&VS_SIGNAL);
- }
- else {
- NutIrqDisable(&VS_SIGNAL);
- }
- is_enabled = enable;
- return rc;
- }
- /*
- * \brief Feed the decoder with data.
- *
- * This function serves two purposes:
- * - It is called by VsPlayerKick() to initially fill the decoder buffer.
- * - It is used as an interrupt handler for the decoder.
- */
- static void VsPlayerFeed(void *arg)
- {
- uint8_t ief;
- uint8_t j = 32;
- size_t total = 0;
- if (bit_is_clear(VS_DREQ_PIN, VS_DREQ_BIT)) {
- return;
- }
- /*
- * We are hanging around here some time and may block other important
- * interrupts. Disable decoder interrupts and enable global interrupts.
- */
- ief = VsPlayerInterrupts(0);
- sei();
- /*
- * Feed the decoder until its buffer is full or we ran out of data.
- */
- if (vs_status == VS_STATUS_RUNNING) {
- char *bp = 0;
- size_t consumed = 0;
- size_t available = 0;
- do {
- if(consumed >= available) {
- /* Commit previously consumed bytes. */
- if(consumed) {
- NutSegBufReadCommit(consumed);
- consumed = 0;
- }
- /* All bytes consumed, request new. */
- bp = NutSegBufReadRequest(&available);
- if(available == 0) {
- /* End of stream. */
- vs_status = VS_STATUS_EOF;
- break;
- }
- }
- /* We have some data in the buffer, feed it. */
- VsSdiPutByte(*bp);
- bp++;
- consumed++;
- total++;
- if (total > 4096) {
- vs_status = VS_STATUS_EOF;
- break;
- }
- /* Allow 32 bytes to be sent as long as DREQ is set, This includes
- the one in progress. */
- if (bit_is_set(VS_DREQ_PIN, VS_DREQ_BIT))
- j = 32;
- } while(j--);
- /* Finally re-enable the producer buffer. */
- NutSegBufReadLast(consumed);
- }
- /*
- * Flush the internal VS buffer.
- */
- if(vs_status != VS_STATUS_RUNNING && vs_flush) {
- do {
- VsSdiPutByte(0);
- if (--vs_flush == 0) {
- /* Decoder internal buffer is flushed. */
- vs_status = VS_STATUS_EMPTY;
- break;
- }
- /* Allow 32 bytes to be sent as long as DREQ is set, This includes
- the one in progress. */
- if (bit_is_set(VS_DREQ_PIN, VS_DREQ_BIT))
- j = 32;
- } while(j--);
- }
- VsPlayerInterrupts(ief);
- }
- /*!
- * \brief Start playback.
- *
- * This routine will send the first MP3 data bytes to the
- * decoder, until it is completely filled. The data buffer
- * should have been filled before calling this routine.
- *
- * Decoder interrupts will be enabled.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerKick(void)
- {
- /*
- * Start feeding the decoder with data.
- */
- VsPlayerInterrupts(0);
- vs_status = VS_STATUS_RUNNING;
- VsPlayerFeed(NULL);
- VsPlayerInterrupts(1);
- return 0;
- }
- /*!
- * \brief Stops the playback.
- *
- * This routine will stops the MP3 playback, VsPlayerKick() may be used
- * to resume the playback.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerStop(void)
- {
- uint8_t ief;
- ief = VsPlayerInterrupts(0);
- /* Check whether we need to stop at all to not overwrite other than running status */
- if (vs_status == VS_STATUS_RUNNING) {
- vs_status = VS_STATUS_STOPPED;
- }
- VsPlayerInterrupts(ief);
- return 0;
- }
- /*!
- * \brief Sets up decoder internal buffer flushing.
- *
- * This routine will set up internal VS buffer flushing,
- * unless the buffer is already empty and starts the playback
- * if necessary. The internal VS buffer is flushed in VsPlayerFeed()
- * at the end of the stream.
- *
- * Decoder interrupts will be enabled.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerFlush(void)
- {
- VsPlayerInterrupts(0);
- /* Set up fluhing unless both buffers are empty. */
- if (vs_status != VS_STATUS_EMPTY || NutSegBufUsed()) {
- if (vs_flush == 0)
- vs_flush = VS_FLUSH_BYTES;
- /* start the playback if necessary */
- if (vs_status != VS_STATUS_RUNNING)
- VsPlayerKick();
- }
- VsPlayerInterrupts(1);
- return 0;
- }
- /*!
- * \brief Initialize the VS1001 hardware interface.
- *
- * \note The interrupt handler for this device uses a significant amount
- * of stack space, which may require to increase thread stacks of
- * all running threads. Furthermore, it requires quite some time
- * to execute and may degrade overall system performance.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerInit(void)
- {
- /* Disable decoder interrupts. */
- VsPlayerInterrupts(0);
- /* Keep decoder in reset state. */
- cbi(VS_RESET_PORT, VS_RESET_BIT);
- sbi(VS_RESET_DDR, VS_RESET_BIT);
- /* Set BSYNC output low. */
- cbi(VS_BSYNC_PORT, VS_BSYNC_BIT);
- sbi(VS_BSYNC_DDR, VS_BSYNC_BIT);
- /* Set MP3 chip select output low. */
- sbi(VS_XCS_PORT, VS_XCS_BIT);
- sbi(VS_XCS_DDR, VS_XCS_BIT);
- /* Set DREQ input with pullup. */
- sbi(VS_DREQ_PORT, VS_DREQ_BIT);
- cbi(VS_DREQ_DDR, VS_DREQ_BIT);
- /* Init SPI Port. */
- sbi(VS_SI_DDR, VS_SI_BIT);
- sbi(VS_SS_DDR, VS_SS_BIT);
- cbi(VS_SO_DDR, VS_SO_BIT);
- /* Set SCK output low. */
- cbi(VS_SCK_PORT, VS_SCK_BIT);
- sbi(VS_SCK_DDR, VS_SCK_BIT);
- #ifndef VS_NOSPI
- {
- uint8_t dummy; /* Required by some compilers. */
- /*
- * Init SPI mode to no interrupts, enabled, MSB first, master mode,
- * rising clock and fosc/4 clock speed. Send an initial zero byte to
- * make sure SPIF is set. Note, that the decoder reset line is still
- * active.
- */
- outb(SPCR, BV(MSTR) | BV(SPE));
- dummy = inb(SPSR);
- outb(SPDR, 0);
- }
- #endif
- /* Register the interrupt routine */
- if (NutRegisterIrqHandler(&VS_SIGNAL, VsPlayerFeed, NULL)) {
- return -1;
- }
- /* Rising edge will generate interrupts. */
- NutIrqSetMode(&VS_SIGNAL, NUT_IRQMODE_RISINGEDGE);
- /* Release decoder reset line. */
- sbi(VS_RESET_PORT, VS_RESET_BIT);
- NutDelay(4);
- /* Force frequency change (see datasheet). */
- VsRegWrite(VS_CLOCKF_REG, 0x9800);
- VsRegWrite(VS_INT_FCTLH_REG, 0x8008);
- NutDelay(200);
- /* Clear any spurious interrupt. */
- outb(EIFR, BV(VS_DREQ_BIT));
- return 0;
- }
- /*!
- * \brief Software reset the decoder.
- *
- * This function is typically called after VsPlayerInit() and at the end
- * of each track.
- *
- * \param mode Any of the following flags may be or'ed
- * - VS_SM_DIFF Left channel inverted.
- * - VS_SM_FFWD Fast forward.
- * - VS_SM_RESET Force hardware reset.
- * - VS_SM_PDOWN Switch to power down mode.
- * - VS_SM_BASS Bass/treble enhancer.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerReset(uint16_t mode)
- {
- /* Disable decoder interrupts and feeding. */
- VsPlayerInterrupts(0);
- vs_status = VS_STATUS_STOPPED;
- /* Software reset, set modes of decoder. */
- VsRegWrite(VS_MODE_REG, VS_SM_RESET | mode);
- NutDelay(2);
- /*
- * Check for correct reset.
- */
- if ((mode & VS_SM_RESET) != 0 || bit_is_clear(VS_DREQ_PIN, VS_DREQ_BIT)) {
- /* If not succeeded, give it one more chance and try hw reset,
- HW reset may also be forced by VS_SM_RESET mode bit. */
- cbi(VS_RESET_PORT, VS_RESET_BIT);
- _NOP();
- sbi(VS_RESET_PORT, VS_RESET_BIT);
- NutDelay(4);
- /* Set the requested modes. */
- VsRegWrite(VS_MODE_REG, VS_SM_RESET | mode);
- NutDelay(2);
- if (bit_is_clear(VS_DREQ_PIN, VS_DREQ_BIT))
- return -1;
- }
- /* Force frequency change (see datasheet). */
- VsRegWrite(VS_CLOCKF_REG, 0x9800);
- VsRegWrite(VS_INT_FCTLH_REG, 0x8008);
- NutDelay(2);
- /* Clear any spurious interrupts. */
- outb(EIFR, BV(VS_DREQ_BIT));
- return 0;
- }
- /*!
- * \brief Set mode register of the decoder.
- *
- * \param mode Any of the following flags may be or'ed
- * - VS_SM_DIFF Left channel inverted.
- * - VS_SM_FFWD Fast forward.
- * - VS_SM_RESET Software reset.
- * - VS_SM_PDOWN Switch to power down mode.
- * - VS_SM_BASS Bass/treble enhancer.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsPlayerSetMode(uint16_t mode)
- {
- uint8_t ief;
- ief = VsPlayerInterrupts(0);
- VsRegWrite(VS_MODE_REG, mode);
- VsPlayerInterrupts(ief);
- return 0;
- }
- /*!
- * \brief Returns play time since last reset.
- *
- * \return Play time since reset in seconds
- */
- uint16_t VsPlayTime(void)
- {
- uint16_t rc;
- uint8_t ief;
- ief = VsPlayerInterrupts(0);
- rc = VsRegRead(VS_DECODE_TIME_REG);
- VsPlayerInterrupts(ief);
- return rc;
- }
- /*!
- * \brief Returns status of the player.
- *
- * \return Any of the following value:
- * - VS_STATUS_STOPPED Player is ready to be started by VsPlayerKick().
- * - VS_STATUS_RUNNING Player is running.
- * - VS_STATUS_EOF Player has reached the end of a stream after VsPlayerFlush() has been called.
- * - VS_STATUS_EMPTY Player runs out of data. VsPlayerKick() will restart it.
- */
- uint8_t VsGetStatus(void)
- {
- return vs_status;
- }
- #ifdef __GNUC__
- /*!
- * \brief Query MP3 stream header information.
- *
- * \param vshi Pointer to VS_HEADERINFO structure.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsGetHeaderInfo(VS_HEADERINFO * vshi)
- {
- uint16_t *usp = (uint16_t *) vshi;
- uint8_t ief;
- ief = VsPlayerInterrupts(0);
- *usp = VsRegRead(VS_HDAT1_REG);
- *++usp = VsRegRead(VS_HDAT0_REG);
- VsPlayerInterrupts(ief);
- return 0;
- }
- #endif
- /*!
- * \brief Initialize decoder memory test and return result.
- *
- * \return Memory test result.
- * - Bit 0: Good X ROM
- * - Bit 1: Good Y ROM (high)
- * - Bit 2: Good Y ROM (low)
- * - Bit 3: Good Y RAM
- * - Bit 4: Good X RAM
- * - Bit 5: Good Instruction RAM (high)
- * - Bit 6: Good Instruction RAM (low)
- */
- uint16_t VsMemoryTest(void)
- {
- uint16_t rc;
- uint8_t ief;
- static const char mtcmd[] PROGMEM = { 0x4D, 0xEA, 0x6D, 0x54, 0x00, 0x00, 0x00, 0x00 };
- ief = VsPlayerInterrupts(0);
- VsSdiWrite_P(mtcmd, sizeof(mtcmd));
- NutDelay(40);
- rc = VsRegRead(VS_HDAT0_REG);
- VsPlayerInterrupts(ief);
- return rc;
- }
- /*!
- * \brief Set volume.
- *
- * \param left Left channel volume.
- * \param right Right channel volume.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsSetVolume(uint8_t left, uint8_t right)
- {
- uint8_t ief;
- ief = VsPlayerInterrupts(0);
- VsRegWrite(VS_VOL_REG, (((uint16_t) left) << 8) | (uint16_t) right);
- VsPlayerInterrupts(ief);
- return 0;
- }
- /*!
- * \brief Sine wave beep.
- *
- * \param fsin Frequency.
- * \param ms Duration.
- *
- * \return 0 on success, -1 otherwise.
- */
- int VsBeep(uint8_t fsin, uint8_t ms)
- {
- uint8_t ief;
- static const char on[] PROGMEM = { 0x53, 0xEF, 0x6E };
- static const char off[] PROGMEM = { 0x45, 0x78, 0x69, 0x74 };
- static const char end[] PROGMEM = { 0x00, 0x00, 0x00, 0x00 };
- /* Disable decoder interrupts. */
- ief = VsPlayerInterrupts(0);
- fsin = 56 + (fsin & 7) * 9;
- VsSdiWrite_P(on, sizeof(on));
- VsSdiWrite(&fsin, 1);
- VsSdiWrite_P(end, sizeof(end));
- NutDelay(ms);
- VsSdiWrite_P(off, sizeof(off));
- VsSdiWrite_P(end, sizeof(end));
- /* Enable decoder interrupts. */
- VsPlayerInterrupts(ief);
- return 0;
- }
- /*@}*/
|