WM8904: Add reset logic to put the part back in its initial state after playing each WAV file. Base samles per second on frame length, not bits-per-sample. Use a different frame length for 8-bit and 16-bit data
This commit is contained in:
parent
23024b2d6a
commit
8065ab73a4
@ -184,6 +184,12 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv);
|
||||
#if 0 /* Not used */
|
||||
static void wm8904_audio_input(FAR struct wm8904_dev_s *priv);
|
||||
#endif
|
||||
#ifdef WM8904_USE_FFLOCK_INT
|
||||
static void wm8904_configure_ints(FAR struct wm8904_dev_s *priv);
|
||||
#else
|
||||
# define wm8904_configure_ints(p)
|
||||
#endif
|
||||
static void wm8904_hw_reset(FAR struct wm8904_dev_s *priv);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
@ -627,6 +633,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
||||
unsigned int fllndx;
|
||||
unsigned int divndx;
|
||||
unsigned int outdiv;
|
||||
unsigned int framelen;
|
||||
#ifdef WM8904_USE_FFLOCK_INT
|
||||
bool enabled;
|
||||
int retries;
|
||||
@ -634,22 +641,21 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
||||
|
||||
DEBUGASSERT(priv && priv->lower);
|
||||
|
||||
/* First calculate the desired bitrate (fout) */
|
||||
|
||||
#if 0
|
||||
/* This is the correct calculation. However, the resulting bitrate is two
|
||||
* times too fast???
|
||||
/* First calculate the desired bitrate (fout). This is based on
|
||||
*
|
||||
* 1. The I2S frame length (in bits)
|
||||
* 2. The number of frames per second = nchannnels * samplerate
|
||||
*/
|
||||
|
||||
fout = (uint32_t)priv->samprate * (uint32_t)priv->nchannels * (uint32_t)priv->bpsamp;
|
||||
#else
|
||||
/* Ahhh.. much better */
|
||||
framelen = (priv->bpsamp == 8) ? WM8904_FRAMELEN8 : WM8904_FRAMELEN16;
|
||||
fout = (uint32_t)priv->samprate * (uint32_t)priv->nchannels * framelen;
|
||||
|
||||
fout = (uint32_t)priv->samprate * (uint32_t)priv->bpsamp;
|
||||
#endif
|
||||
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(framelen << 1);
|
||||
wm8904_writereg(priv, WM8904_AIF3, regval);
|
||||
|
||||
audvdbg("sample rate=%u nchannels=%u bpsamp=%u fout=%lu\n",
|
||||
priv->samprate, priv->nchannels, priv->bpsamp, (unsigned long)fout);
|
||||
audvdbg("sample rate=%u nchannels=%u bpsamp=%u framelen=%d fout=%lu\n",
|
||||
priv->samprate, priv->nchannels, priv->bpsamp, framelen,
|
||||
(unsigned long)fout);
|
||||
|
||||
/* Disable the SYSCLK.
|
||||
*
|
||||
@ -1273,9 +1279,8 @@ static int wm8904_shutdown(FAR struct audio_lowerhalf_s *dev)
|
||||
/* Now issue a software reset. This puts all WM8904 registers back in
|
||||
* their default state.
|
||||
*/
|
||||
/* REVISIT: But then the register configuration is lost. */
|
||||
/* wm8904_writereg(priv, WM8904_SWRST, 0); */
|
||||
|
||||
wm8904_hw_reset(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -2068,15 +2073,9 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the WM8904 interrupt */
|
||||
/* Reset the WM8904 hardware */
|
||||
|
||||
WM8904_DISABLE(priv->lower);
|
||||
|
||||
/* Mute the volume and disable the FLL output */
|
||||
|
||||
wm8904_setvolume(priv, priv->volume, true);
|
||||
wm8904_writereg(priv, WM8904_FLL_CTRL1, 0);
|
||||
wm8904_writereg(priv, WM8904_DUMMY, 0x55aa);
|
||||
wm8904_hw_reset(priv);
|
||||
|
||||
/* Return any pending buffers in our pending queue */
|
||||
|
||||
@ -2248,13 +2247,13 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
||||
|
||||
/* Audio Interface 3
|
||||
*
|
||||
* Set LRCLK as an output with rate = BCLK / 64. This is a constant value
|
||||
* used with audio. Since I2S will send a word on each edge of LRCLK (after
|
||||
* a delay), this essentially means that each audio frame is 32 bits in
|
||||
* length;
|
||||
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This is
|
||||
* a value that varies with bits per sample, n=8 or 16. Since I2S will send
|
||||
* a word on each edge of LRCLK (after a delay), this essentially means that
|
||||
* each audio frame is WM8904_FRAMELENn bits in length.
|
||||
*/
|
||||
|
||||
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(64);
|
||||
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(2*WM8904_FRAMELEN16);
|
||||
wm8904_writereg(priv, WM8904_AIF3, regval);
|
||||
|
||||
/* DAC Digital 1 */
|
||||
@ -2308,7 +2307,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
||||
* function then modifies the configuration to support audio input.
|
||||
*
|
||||
* Input Parameters:
|
||||
* prive - A reference to the driver state structure
|
||||
* priv - A reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None. No failures are detected.
|
||||
@ -2336,6 +2335,98 @@ static void wm8904_audio_input(FAR struct wm8904_dev_s *priv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: wm8904_configure_ints
|
||||
*
|
||||
* Description:
|
||||
* Configure the GPIO/IRQ interrupt
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef WM8904_USE_FFLOCK_INT
|
||||
static void wm8904_configure_ints(FAR struct wm8904_dev_s *priv)
|
||||
{
|
||||
uint16_t regval;
|
||||
|
||||
/* Configure GPIO1 as an IRQ
|
||||
*
|
||||
* WM8904_GPIO1_PU=0 : No pull-up
|
||||
* WM8904_GPIO1_PD=1 : Pulled-down
|
||||
* WM8904_GPIO1_SEL_IRQ : Configured as IRQ
|
||||
*/
|
||||
|
||||
regval = (WM8904_GPIO1_SEL_IRQ | WM8904_GPIO1_PD);
|
||||
wm8904_writereg(priv, WM8904_GPIO_CTRL1, regval);
|
||||
|
||||
/* Attach our handler to the GPIO1/IRQ interrupt */
|
||||
|
||||
WM8904_ATTACH(lower, wm8904_interrupt, priv);
|
||||
|
||||
/* Configure interrupts. wm8904_setbitrate() depends on FLL interrupts. */
|
||||
|
||||
wm8904_writereg(priv, WM8904_INT_STATUS, WM8904_ALL_INTS);
|
||||
wm8904_writereg(priv, WM8904_INT_MASK, WM8904_ALL_INTS);
|
||||
wm8904_writereg(priv, WM8904_INT_POL, 0);
|
||||
wm8904_writereg(priv, WM8904_INT_DEBOUNCE, WM8904_ALL_INTS);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: wm8904_hw_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset and re-initialize the WM8904
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void wm8904_hw_reset(FAR struct wm8904_dev_s *priv)
|
||||
{
|
||||
/* Put audio output back to its initial configuration */
|
||||
|
||||
priv->samprate = WM8904_DEFAULT_SAMPRATE;
|
||||
priv->nchannels = WM8904_DEFAULT_NCHANNELS;
|
||||
priv->bpsamp = WM8904_DEFAULT_BPSAMP;
|
||||
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
|
||||
priv->balance = b16HALF; /* Center balance */
|
||||
#endif
|
||||
|
||||
/* Software reset. This puts all WM8904 registers back in their
|
||||
* default state.
|
||||
*/
|
||||
|
||||
wm8904_writereg(priv, WM8904_SWRST, 0);
|
||||
|
||||
/* Configure the WM8904 hardware as an audio input device */
|
||||
|
||||
wm8904_audio_output(priv);
|
||||
|
||||
/* Configure interrupts */
|
||||
|
||||
wm8904_configure_ints(priv);
|
||||
|
||||
/* Configure the FLL and the LRCLK */
|
||||
|
||||
wm8904_setbitrate(priv);
|
||||
wm8904_writereg(priv, WM8904_DUMMY, 0x55aa);
|
||||
|
||||
/* Dump some information and return the device instance */
|
||||
|
||||
wm8904_dump_registers(&priv->dev, "After configuration");
|
||||
wm8904_clock_analysis(&priv->dev, "After configuration");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -2381,12 +2472,6 @@ FAR struct audio_lowerhalf_s *
|
||||
priv->lower = lower;
|
||||
priv->i2c = i2c;
|
||||
priv->i2s = i2s;
|
||||
priv->samprate = WM8904_DEFAULT_SAMPRATE;
|
||||
priv->nchannels = WM8904_DEFAULT_NCHANNELS;
|
||||
priv->bpsamp = WM8904_DEFAULT_BPSAMP;
|
||||
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
|
||||
priv->balance = b16HALF; /* Center balance */
|
||||
#endif
|
||||
|
||||
sem_init(&priv->pendsem, 0, 1);
|
||||
dq_init(&priv->pendq);
|
||||
@ -2414,42 +2499,9 @@ FAR struct audio_lowerhalf_s *
|
||||
goto errout_with_dev;
|
||||
}
|
||||
|
||||
/* Configure the WM8904 hardware as an audio input device */
|
||||
/* Reset and reconfigure the WM8904 hardwaqre */
|
||||
|
||||
wm8904_audio_output(priv);
|
||||
|
||||
#ifdef WM8904_USE_FFLOCK_INT
|
||||
/* Configure GPIO1 as an IRQ
|
||||
*
|
||||
* WM8904_GPIO1_PU=0 : No pull-up
|
||||
* WM8904_GPIO1_PD=1 : Pulled-down
|
||||
* WM8904_GPIO1_SEL_IRQ : Configured as IRQ
|
||||
*/
|
||||
|
||||
regval = (WM8904_GPIO1_SEL_IRQ | WM8904_GPIO1_PD);
|
||||
wm8904_writereg(priv, WM8904_GPIO_CTRL1, regval);
|
||||
|
||||
/* Attach our handler to the GPIO1/IRQ interrupt */
|
||||
|
||||
WM8904_ATTACH(lower, wm8904_interrupt, priv);
|
||||
|
||||
/* Configure interrupts. wm8904_setbitrate() depends on FLL interrupts. */
|
||||
|
||||
wm8904_writereg(priv, WM8904_INT_STATUS, WM8904_ALL_INTS);
|
||||
wm8904_writereg(priv, WM8904_INT_MASK, WM8904_ALL_INTS);
|
||||
wm8904_writereg(priv, WM8904_INT_POL, 0);
|
||||
wm8904_writereg(priv, WM8904_INT_DEBOUNCE, WM8904_ALL_INTS);
|
||||
#endif
|
||||
|
||||
/* Configure the FLL and the LRCLK */
|
||||
|
||||
wm8904_setbitrate(priv);
|
||||
wm8904_writereg(priv, WM8904_DUMMY, 0x55aa);
|
||||
|
||||
/* Dump some information and return the device instance */
|
||||
|
||||
wm8904_dump_registers(&priv->dev, "After configuration");
|
||||
wm8904_clock_analysis(&priv->dev, "After configuration");
|
||||
wm8904_hw_reset(priv);
|
||||
return &priv->dev;
|
||||
}
|
||||
|
||||
|
@ -1015,24 +1015,27 @@
|
||||
/* FLL Configuration *********************************************************/
|
||||
/* Default FLL configuration */
|
||||
|
||||
#define WM8904_DEFAULT_SAMPRATE 11025
|
||||
#define WM8904_DEFAULT_NCHANNELS 1
|
||||
#define WM8904_DEFAULT_BPSAMP 16
|
||||
#define WM8904_DEFAULT_SAMPRATE 11025 /* Initial sample rate */
|
||||
#define WM8904_DEFAULT_NCHANNELS 1 /* Initial number of channels */
|
||||
#define WM8904_DEFAULT_BPSAMP 16 /* Initial bits per sample */
|
||||
|
||||
#define WM8904_NFLLRATIO_DIV1 0
|
||||
#define WM8904_NFLLRATIO_DIV1 0 /* Values of the FLL_RATIO field */
|
||||
#define WM8904_NFLLRATIO_DIV2 1
|
||||
#define WM8904_NFLLRATIO_DIV4 2
|
||||
#define WM8904_NFLLRATIO_DIV8 3
|
||||
#define WM8904_NFLLRATIO_DIV16 4
|
||||
#define WM8904_NFLLRATIO 5
|
||||
#define WM8904_NFLLRATIO 5 /* Number of FLL_RATIO values */
|
||||
|
||||
#define WM8904_MINOUTDIV 4
|
||||
#define WM8904_MAXOUTDIV 64
|
||||
#define WM8904_MINOUTDIV 4 /* Minimum FLL_OUTDIV divider */
|
||||
#define WM8904_MAXOUTDIV 64 /* Maximum FLL_OUTDIV divider */
|
||||
|
||||
#define WM8904_BCLK_MAXDIV 20
|
||||
#define WM8904_BCLK_MAXDIV 20 /* Maximum BCLK divider */
|
||||
|
||||
#define WM8904_FVCO_MIN 90000000
|
||||
#define WM8904_FVCO_MAX 100000000
|
||||
#define WM8904_FVCO_MIN 90000000 /* Minimum value of Fvco */
|
||||
#define WM8904_FVCO_MAX 100000000 /* Maximum value of Fvco */
|
||||
|
||||
#define WM8904_FRAMELEN8 14 /* Bits per frame for 8-bit data */
|
||||
#define WM8904_FRAMELEN16 32 /* Bits per frame for 16-bit data */
|
||||
|
||||
/* Commonly defined and redefined macros */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user