📄 vs1001k.c
字号:
/* * Copyright (C) 2003 by Pavel Chromy. All rights reserved. * Copyright (C) 2001-2003 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 EGNITE SOFTWARE GMBH 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 EGNITE * SOFTWARE GMBH 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. *//* * $Log: vs1001k.c,v $ * Revision 1.1 2003/07/21 18:09:51 haraldkipp * Backup of old driver * * Revision 1.1.1.1 2003/05/09 14:40:58 haraldkipp * Initial using 3.2.1 * * Revision 1.12 2003/05/06 18:35:21 harald * ICCAVR port * * Revision 1.11 2003/04/21 16:43:54 harald * Added more comments. * Avoid initializing static globals to zero. * New function VsSdiWrite/_P checks DREQ * Removed decoder interrupt en/disable from low level routines. * Keep decoder in reset state until ports have been initialized. * Do not send initial zero bytes as the datasheet recommends. * A single nop is sufficient delay during reset active. * Clear interrupt flag after reset to avoid useless interrupt. * Available buffer size corrected. * New function to read header information. * New function invokes decoder memory test. * Beep makes use of VsSdiWrite. * * Revision 1.10 2003/04/18 14:46:08 harald * Copyright update by the maintainer, after none of the original code had * been left. We have a clean BSD licence now. * This release had been prepared by Pavel Chromy. * BSYNC vs. transfer in progress issue in VsSdiPutByte(). * Fixed possible transfer in progress issue in VsPlayerFeed(). * HW reset may be forced by VS_SM_RESET mode bit * * Revision 1.9 2003/04/07 20:29:20 harald * Redesigned by Pavel Chromy * * Revision 1.9 2003/04/04 15:01:00 mac * VS_STATUS_EMTY is reported correctly. * * Revision 1.9 2003/02/14 13:39:00 mac * Several serious bugs fixed, * interrupt routine completely remade. * Unreliable spurious interrupts detection removed. * Mpeg frame detection removed. * Watermark check removed (this was rather limiting) * Can be optionaly compiled not to use SPI * * Revision 1.8 2003/02/04 17:50:55 harald * Version 3 released * * Revision 1.7 2003/01/14 16:15:19 harald * Sending twice the number of zeros to end MP3 stream. * Check for spurious interrupts to detect hanging chip. * Simpler portable inline assembler for short delays. * * Revision 1.6 2002/11/02 15:15:13 harald * Library dependencies removed * * Revision 1.5 2002/09/15 16:44:14 harald * *** empty log message *** * * Revision 1.4 2002/08/16 17:49:02 harald * First public release * * Revision 1.3 2002/06/26 17:29:08 harald * First pre-release with 2.4 stack * */#include <sys/atom.h>#include <sys/event.h>#include <sys/timer.h>#include <sys/heap.h>#include <dev/irqreg.h>#include <dev/vs1001k.h>/*! * \addtogroup xgVs1001 *//*@{*/static volatile u_char vs_status = VS_STATUS_STOPPED;static volatile u_short vs_flush;static u_char *vs_databuff;static u_char *vs_dataend;static u_char *vs_writeptr;static u_char *volatile vs_readptr;/* * \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(u_char b){#ifdef VS_NOSPI u_char 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); outp(b, SPDR); _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 u_char * data, u_short len){ u_short 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, u_short len){ u_short 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(u_char data){ u_char 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 u_char VsSciGetByte(void){ u_char mask = 0x80; u_char 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(u_char reg, u_short 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((u_char) (data >> 8)); VsSciPutByte((u_char) data);#ifndef VS_NOSPI /* Re-enable SPI. Hint given by Jesper Hansen. */ outp(BV(MSTR) | BV(SPE), SPCR); outp(inp(SPSR), 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 u_short VsRegRead(u_char reg){ u_short data; /* Disable interrupts and select chip. */ cbi(EIMSK, VS_DREQ_BIT); cbi(VS_XCS_PORT, VS_XCS_BIT);#ifndef VS_NOSPI /* Disable SPI. */ cbi(SPCR, SPE);#endif VsSciPutByte(VS_OPCODE_READ); VsSciPutByte(reg); data = VsSciGetByte() << 8; data |= VsSciGetByte();#ifndef VS_NOSPI /* Re-enable SPI. Changed due to a hint by Jesper. */ outp(BV(MSTR) | BV(SPE), SPCR); outp(inp(SPSR), SPSR);#endif /* Deselect chip and enable interrupts. */ sbi(VS_XCS_PORT, VS_XCS_BIT); sbi(EIMSK, VS_DREQ_BIT); return data;}/* * \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){ u_char j; /* Cancel interrupt if not running. */ if (vs_status != VS_STATUS_RUNNING) return; /* We may feed 32 bytes to the decoder. */ if (bit_is_set(VS_DREQ_PIN, VS_DREQ_BIT)) j = 32; else j = 0; /* * Feed the decoder until its buffer is full. */ while (j--) { /* Is main buffer empty? */ if (vs_readptr == vs_writeptr) { if (vs_flush) { /* Auto flush the internal VS buffer. */ VsSdiPutByte(0); if (--vs_flush == 0) { /* Decoder internal buffer is flushed. */ vs_status = VS_STATUS_EMPTY; break; } } else { /* End of stream. */ vs_status = VS_STATUS_EOF; break; } } /* We have some data in the buffer, feed it. */ else { VsSdiPutByte(*vs_readptr); if (++vs_readptr == vs_dataend) vs_readptr = vs_databuff; } /* If DREQ is high, allow 31 bytes to be sent, SPI transfer may still be in progress, which is the 32nd byte. */ if (bit_is_set(VS_DREQ_PIN, VS_DREQ_BIT)) j = 31; }}/*! * \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. * * \return 0 on success, -1 otherwise. */int VsPlayerKick(void){ cbi(EIMSK, VS_DREQ_BIT); /* * Start feeding the decoder with data and * enable interrupts. */ vs_status = VS_STATUS_RUNNING; VsPlayerFeed(NULL); sbi(EIMSK, VS_DREQ_BIT); return 0;}/*! * \brief Stops the playback. * * This routine will stops the MP3 playback, VsPlayerKick() may be used * to resume the playback. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -