⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sta013.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
字号:
//++
//sta013.c - STA013 MP3 decoder functions
//
// Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA  02111-1307  USA.
//
//DESCRIPTION:
//
//
//REFERENCES:
//	http://hubbard.engr.scu.edu/embedded/avr/avrlib/docs/html/sta013_8h.html
//	http://hubbard.engr.scu.edu/embedded/avr/avrlib/docs/html/sta013_8c.html
//	http://www.pjrc.com/tech/mp3/sta013.html
//
//REVISION HISTORY:
// dd-mmm-yy    who     description
// 15-May-05	RLA	New file.
// 15-Oct-05	RLA	Add VOLUME conditional.
// 19-OCT-05	RLA	Add ResetMP3Decoder().  Split up the P02_0609 data
//			 into the UpdateData[] and ConfigData[] arrays. This
//			 cleans up the noise burst (part of the previous song,
//			 actually) when turning the knob.
//--

// Include files...
#include <stdio.h>		// needed so DBGOUT(()) can find printf!
#include "standard.h"		// standard types - BYTE, WORD, BOOL, etc
#include "reg66x.h"		// declarations for Philips 89C66x processors
#include "player.h"		// project wide (hardware configuration) declarations
#include "debug.h"		// debugging stuff and ResetWDT()
#include "post.h"		// POST codes for Fail()
#include "timer.h"		// timer and time functions
#include "i2c.h"		// low level STA013 I2C communcations routines
#include "buffer.h"		// disk sector buffer functions
#include "sta013.h"		// declarations for this module

//   It turns out that the STA013 isn't good for much of anything right after a
// reset.  In fact, it can't even decode MP3 files until it has been properly
// "updated" first; according to ST this process is mandatory!  ST provides an
// update file on their web page; this file is really nothing more than a list of
// register addresses, register value pairs.
PRIVATE const BYTE CODE m_abUpdateData[] = {
#include "p02_0609.h"
};

//   After the STA013 has been updated, it must be configured to work with the
// rest of our hardware.  This includes things like programming the PLL dividers
// to work with our 14.31818MHz clock (the STA013 clock, NOT the MCU clock!),
// programming the output data format to be compatible with the CS4334, and
// setting the DRQ and IRQ polarities.  ST originally included a lot of this
// information in their P02_0609 patch file, but it doesn't really belong there
// since it is specific to our hardware.  Note also that, unlike the update data,
// this information does not survive a STA013 soft reset!
//
//   WARNING! The _order_ in which these registers are written is important!
// If you're tempted to re-arrange the order of the lines in this table just
// for cosmetic purposes, go lie down until the urge goes away...
PRIVATE const BYTE CODE m_abConfigData[] = {
  58,			   0, 	// undocumented
  STA_REG_PCMDIVIDER,      1, 	// 256X oversample, 32 bit words
  STA_REG_PCMCONF,  	  33,	// I2S format for CS4334

  //   The following section gives the PPL configration for various crystal
  // frequencies.  You can generate your own for almost any crystal by using
  // the CPLL.EXE program from the ST web site (see the URL given above)...
#if STA013_CLOCK == 14745600L
  STA_REG_PLLCTL_N,        0, 	// PLLCTL (N)		
  STA_REG_PLLCTL_M,       12,	// PLLCTL (M)
  11,			   3,	// undocumented (but CPLL generates it!)
  STA_REG_MFSDF_441,      16,	// MFSDF_441
  STA_REG_PLLFRAC_441_L,   0,	// PLLFRAC_441_L
  STA_REG_PLLFRAC_441_H,   4,	// PLLFRAC_441_H
  STA_REG_MFSDF,  	  15,	// MFSDF (X)
  STA_REG_PLLFRAC_L,  	  85,	// PLLFRAC_L
  STA_REG_PLLFRAC_H,  	  85,	// PLLFRAC_H
#elif STA013_CLOCK == 14318180L
  STA_REG_PLLCTL_N,        0,	// PLLCTL (N)		
  STA_REG_PLLCTL_M,  	  12,	// PLLCTL (M)
  11, 			   3, 	// undocumented
  STA_REG_MFSDF_441,      16,	// MFSDF_441
  STA_REG_PLLFRAC_441_L, 119,	// PLLFRAC_441_L
  STA_REG_PLLFRAC_441_H, 103,	// PLLFRAC_441_H
  STA_REG_MFSDF,  	  15,	// MFSDF (X)
  STA_REG_PLLFRAC_L,      58,	// PLLFRAC_L
  STA_REG_PLLFRAC_H,     187,	// PLLFRAC_H
#else
#error UNKNOWN STA013 CLOCK FREQUENCY!!
#endif

  STA_REG_PLLCTL, 	 161,	// enable OCLK/DRQ and update PLL FRAC
//STA_REG_SCLK_POL,   	   4,	// sample SDI on the falling edge of SCKR
  STA_REG_DATA_REQ_ENABLE, 4,	// enable data request pin
  STA_REG_REQ_POL,   	   5 	// send data when DRQ pin is low
};

//   These arrays translate the binary codes returned by the STA013 into actual
// bit rate and sampling frequencies.  Note that there are two sets of bit rates
// - one for MPEG1 and the other for MPEG2 and 2.5.  There are _three_ sets of
// sampling frequences, one each for MPEG 1, 2 and 2.5...
PRIVATE const WORD code m_awMP3BitRates[2][16] = {
  {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}, // MPEG 1 rates 
  {0,  8, 16, 24, 32, 40, 48, 56,  64,  80,  96, 112, 128, 144, 160, 0}  // MPEG2 and 2.5
};
PRIVATE const BYTE code m_abMP3SampleFrequencies[4][4] = {
  {11, 12,  8, 0},	// MPEG 2.5 rates
  { 0,  0,  0, 0},	// (unused)
  {22, 24, 16, 0},	// MPEG 2 rates
  {44, 48, 32, 0}	// MPEG 1 rates
};


//++
//   This routine will send a list of data to the STA013.  The first byte in
// every pair specifies the STA013 register address, and the second byte is
// the data to be sent.  cbData specifies the number of _bytes_ (not words!)
// in the table.
//--
PRIVATE void SendSTA013 (const BYTE CODE *pcbData, WORD cbData)
{
  WORD n;
  //DBGOUT(("SendSTA013: Configuring STA013 ... "));
  for (n = 0;  n < cbData;  n += 2) {
    //DBGOUT(("SendSTA013: register 0x%02bx data 0x%02bx\n", pcbData[n], pcbData[n+1]));
    if (!Write013(pcbData[n], pcbData[n+1])) POST(PC_STA013, FALSE);
  }
  //DBGOUT((" done (%u bytes)\n", cbData));
}

//++
// InitializeSTA013
//--
PUBLIC void InitializeSTA013 (void)
{
  BYTE bVersion;
  // Reset the STA013...
  STA013_RESET = 0;  DelayMS(20);  STA013_RESET = 1;  DelayMS(20);
  // Read the ident register and make sure it's 0xAC...
  if (!Read013(STA_REG_IDENT, &bVersion)) POST(PC_STA013, FALSE);
  if (bVersion != STA_IDENT) POST(PC_STA013, FALSE);
  // Set the DRQ polarity (move this to Configuration File ???)
  DBGOUT(("STA013 initialized (chip version 0x%02bX) ...\n", (BYTE) bVersion));
  SendSTA013(m_abUpdateData, sizeof(m_abUpdateData));
  ResetMP3Decoder();
}

//++
//   This routine will do a soft reset of the STA013 - the main advantage to
// doing this is that it flushes all the internal buffers and pipeline in the
// decoder so that, when we start playing the next song, we don't get a blast
// of noise that's left over data from the previous song!
//
//   This is easily done with the SOFT_RESET register of the STA013, but it
// it's not as simple as that.  According to the documentation, writing this
// register "clears the current command and interrupt registers and puts the
// decoder in idle mode."  Sounds great, but IMHO it's a lie.  Turns out that
// a soft reset also erases all of the PLL, PCM DIVISOR, interface type and
// polarity, and even the volume registers!  If you use soft reset, all these
// have to be re-programmed before STA013 will play anything again!
//
//   One more thing - this function leaves the STA013 muted on return; it's
// up to the caller to unmute...
//--
PUBLIC void ResetMP3Decoder (void)
{
  //   This combination causes a soft reset and the STA013 may need a few
  // microseconds to recover before it can continue.  Many thanks to Paul
  // for pointing this out, http://www.pjrc.com/tech/mp3/sta013.html .
  if (!Write013(STA_REG_SOFT_RESET, 1)) POST(PC_STA013, FALSE);
  //DELAYUS(100);
  if (!Write013(STA_REG_MUTE, 1)) POST(PC_STA013, FALSE);
  // And reconfigure the STA013 for our hardware...
  SendSTA013(m_abConfigData, sizeof(m_abConfigData));
  //DBGOUT(("ResetMP3Decoder: ...\n"));
}


//++
//   This routine sets the MP3 volume, which is specified by a value from zero
// (absolute silence) to 100 (deafening).  In principle these registers can also
// be used to set the balance, but currently that's not implemented.
//--
#ifdef VOLUME
PRIVATE void SetMP3Volume (BYTE bVolume)
{
  //   Conveniently, the STA013 also wants a value from 0..100 for the volume
  // setting.  The catch, however, is that the STA013 registers control an
  // _attenuator_, so the sense of the values is reversed (i.e. zero is maximum
  // volume; 100 is silence).  That's easy enough to fix.
  ASSERT((bVolume <= 100), ("SetMP3Volume: illegal value %bd\n", bVolume));
  if (!Write013(STA_REG_DLA, 100-bVolume)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_DRA, 100-bVolume)) POST(PC_STA013, FALSE);
  //   The STA013 also contains two channel attenuators which would allow you
  // to reverse the left and right channels, mix them both together for a mono
  // output, or reduce the stereo separation by any amount you desire.  Currently
  // we don't use these, so we'll turn them off by setting them to maximum
  // attenuation.
  if (!Write013(STA_REG_DLB, MAX_VOLUME_ATTENUATION)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_DRB, MAX_VOLUME_ATTENUATION)) POST(PC_STA013, FALSE);
  //DBGOUT(("SetMP3Volume: STA013 volume set to %bd%%\n", bVolume));
}
#endif


//++
//   This routine will start the MP3 decoder running, sets the PLAY register
// to one, and then unmutes the output.  Immediately after this (most likely
// before we even have time to return!) the STA013 will assert DRQ and, provided
// that we have data ready to feed it, music will appear.
//--
PUBLIC void StartMP3Decoder (void)
{
#ifdef VOLUME
  SetMP3Volume (VOLUME);
#endif
  if (!Write013(STA_REG_RUN , 1)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_PLAY, 1)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_MUTE, 0)) POST(PC_STA013, FALSE);
  //DBGOUT(("StartMP3Decoder: ...\n"));
}

//++
//   This routine will interrupt the currently playing song and stop the MP3
// decoder.  Unlike the PauseMP3(), this is a destructive stop - it's not
// possible to continue where we left off.  This function is normally used
// to interrupt the current song when the user turns the dial...
//--
PUBLIC void StopMP3Decoder (void)
{
  if (!Write013(STA_REG_MUTE, 1)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_PLAY, 0)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_RUN , 0)) POST(PC_STA013, FALSE);
  //DBGOUT(("StopMP3Decoder: ...\n"));
}


//++
//   This function pauses the current MP3 playback.  This is a clean pause -
// the STA013 stops asserting DRQ and simply idles until playback is resumed
// by calling (what else?) ResumeMP3()...
//--
PUBLIC void PauseMP3 (void)
{
  // Mute the audio and then stop the decoder...
  if (!Write013(STA_REG_MUTE, 1)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_PLAY, 0)) POST(PC_STA013, FALSE);
}

//++
//   Resume playback after a PauseMP3().  WARNING - calling this routine when
// playback is not paused (i.e. when the decoder is stopped will have all sorts
// of unhappy effects.
//--
PUBLIC void ResumeMP3 (void)
{
  // Restart the decoder and unmute the audio...
  if (!Write013(STA_REG_PLAY, 1)) POST(PC_STA013, FALSE);
  if (!Write013(STA_REG_MUTE, 0)) POST(PC_STA013, FALSE);
}


//++
// Return the current MPEG ID from the STA013...
//--
PUBLIC MPEG_ID GetMPEGID (void)
{
  BYTE bHeadH;
  // This value is kept in bits 19..20 of the HEAD[er] register...
  if (!Read013(STA_REG_HEAD_H, &bHeadH)) POST(PC_STA013, FALSE);
  return (bHeadH & 0x18) >> 3;
}

//++
//   Return the bit rate used by the currently playing MP3 file.  Note that
// the return value is in kbps (e.g. 128 for a CD quality sound, 320 for the
// maximum possible MPEG bit rate).
//--
PUBLIC WORD GetMP3BitRate (void)
{
  BYTE bBitRateIndex, bID, bHeadM;
  //   The bitrate is in bits 12..15 of the STA013 HEAD[er] register.  This
  // value is just an index, and unfortunately the meaning of this index
  // depends on whether a MPEG1 or MPEG2/2.5 file is being played.  Once we
  // know these things, we can use the m_awMP3BitRates[][] table to convert
  // to a real k bits per second value.
  if (!Read013(STA_REG_HEAD_M, &bHeadM)) POST(PC_STA013, FALSE);
  bID = GetMPEGID();  bBitRateIndex = (bHeadM & 0xF0) >> 4;
  //DBGOUT(("GetMP3BitRate: bBitRateIndex=%bd, bID=%bd\n", bBitRateIndex, bID));
  return m_awMP3BitRates[(bID==STA_MPEG_1) ? 0 : 1][bBitRateIndex];
}

//++
//   Return the sampling rate used by the currently playing MP3.  The return
// valus is always an integer - e.g 44, 22, etc., for 44.1kHz, 22.05kHz, etc.
//--
PUBLIC BYTE GetMP3SampleFrequency (void)
{
  BYTE bSampleIndex, bID, bHeadM;
  //   The sampling frequency is stored in bits 11..10 of the STA013 HEAD[er]
  // register.  Other than that, it's pretty much the same as the bit rate...
  if (!Read013(STA_REG_HEAD_M, &bHeadM)) POST(PC_STA013, FALSE);
  bID = GetMPEGID();  bSampleIndex = (bHeadM & 0x0C) >> 2;
  //DBGOUT(("GetMP3SampleFrequency: bSampleIndex=%bd, bID=%bd\n", bSampleIndex, bID));
  return m_abMP3SampleFrequencies[bID][bSampleIndex];
}


#if 0
PUBLIC WORD GetMP3AverageBitRate (void)
{
  BYTE bBitRate;
  if (!Read013(STA_REG_AVERAGE_BITRATE, &bBitRate)) POST(PC_STA013, FALSE);
  return bBitRate<<1;
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -