Merged in masayuki2009/nuttx.nuttx/lc823450_i2s_tx_threshold (pull request #667)
arch/arm/src/lc823450: Add tx start threshold to lc823450_i2s.c In addition, lc823450_i2s_send() now accepts byte-aligned stream. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> Approved-by: GregoryN <gnutt@nuttx.org>
This commit is contained in:
parent
f3bb2728d4
commit
88f8a09a25
@ -66,6 +66,8 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* #define SHOW_BUFFERING */
|
||||||
|
|
||||||
#define I2S_HAS_IOCTL
|
#define I2S_HAS_IOCTL
|
||||||
|
|
||||||
#define BUFID(n) (n - 'A')
|
#define BUFID(n) (n - 'A')
|
||||||
@ -193,6 +195,9 @@ struct lc823450_i2s_s
|
|||||||
struct i2s_dev_s dev; /* Externally visible I2S interface */
|
struct i2s_dev_s dev; /* Externally visible I2S interface */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool _b_input_started = false;
|
||||||
|
static uint32_t _i2s_tx_th_bytes;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Function Prototypes
|
* Private Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -398,6 +403,28 @@ static void lc823450_i2s_setchannel(char id, uint8_t ch)
|
|||||||
modifyreg32(ABUFCLR, 0, BUFID(id));
|
modifyreg32(ABUFCLR, 0, BUFID(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _setup_tx_threshold
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void _setup_tx_threshold(uint32_t tx_th)
|
||||||
|
{
|
||||||
|
if (0 == tx_th)
|
||||||
|
{
|
||||||
|
/* default tx threshould : 1024bytes */
|
||||||
|
|
||||||
|
_i2s_tx_th_bytes = 1024;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* tx_th: 0 to 100 (%) */
|
||||||
|
|
||||||
|
_i2s_tx_th_bytes = getreg32(BUF_SIZE('C')) * tx_th / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
putreg32(_i2s_tx_th_bytes, BUF_ULVL('C'));
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: lc823450_i2s_rxdatawidth
|
* Name: lc823450_i2s_rxdatawidth
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -405,6 +432,7 @@ static void lc823450_i2s_setchannel(char id, uint8_t ch)
|
|||||||
static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
|
static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
FAR const struct audio_caps_desc_s *cap_desc;
|
FAR const struct audio_caps_desc_s *cap_desc;
|
||||||
|
uint32_t tx_th;
|
||||||
uint32_t rate[2];
|
uint32_t rate[2];
|
||||||
uint8_t ch[2];
|
uint8_t ch[2];
|
||||||
uint8_t fmt[2];
|
uint8_t fmt[2];
|
||||||
@ -415,12 +443,15 @@ static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
|
|||||||
cap_desc = (FAR const struct audio_caps_desc_s *)((uintptr_t)arg);
|
cap_desc = (FAR const struct audio_caps_desc_s *)((uintptr_t)arg);
|
||||||
ASSERT(NULL != cap_desc);
|
ASSERT(NULL != cap_desc);
|
||||||
|
|
||||||
rate[1] = cap_desc->caps.ac_controls.w;
|
tx_th = cap_desc->caps.ac_controls.w >> 24;
|
||||||
|
rate[1] = cap_desc->caps.ac_controls.w & 0xfffff;
|
||||||
ch[1] = cap_desc->caps.ac_channels;
|
ch[1] = cap_desc->caps.ac_channels;
|
||||||
fmt[1] = cap_desc->caps.ac_format.hw;
|
fmt[1] = cap_desc->caps.ac_format.hw;
|
||||||
|
|
||||||
if (cap_desc->caps.ac_type & AUDIO_TYPE_OUTPUT)
|
if (cap_desc->caps.ac_type & AUDIO_TYPE_OUTPUT)
|
||||||
{
|
{
|
||||||
|
_setup_tx_threshold(tx_th);
|
||||||
|
|
||||||
rate[0] = getreg32(SSRC_FSI) >> 13;
|
rate[0] = getreg32(SSRC_FSI) >> 13;
|
||||||
ch[0] = (getreg32(BUFCTL('C')) & BUFCTL_MONO) ? 1 : 2;
|
ch[0] = (getreg32(BUFCTL('C')) & BUFCTL_MONO) ? 1 : 2;
|
||||||
fmt[0] = getreg32(AUDSEL) & AUDSEL_DECSEL ? AUDIO_FMT_MP3 : AUDIO_FMT_PCM;
|
fmt[0] = getreg32(AUDSEL) & AUDSEL_DECSEL ? AUDIO_FMT_MP3 : AUDIO_FMT_PCM;
|
||||||
@ -480,8 +511,6 @@ static void _i2s_rxdma_callback(DMA_HANDLE hdma, void *arg, int result)
|
|||||||
nxsem_post(waitsem);
|
nxsem_post(waitsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _b_input_started = false;
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: lc823450_i2s_receive
|
* Name: lc823450_i2s_receive
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -629,6 +658,18 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
|||||||
i2s_callback_t callback, void *arg,
|
i2s_callback_t callback, void *arg,
|
||||||
uint32_t timeout)
|
uint32_t timeout)
|
||||||
{
|
{
|
||||||
|
volatile uint32_t *ptr = (uint32_t *)&apb->samp[apb->curbyte];
|
||||||
|
uint32_t n = apb->nbytes;
|
||||||
|
|
||||||
|
if (0 == getreg32(BUF_DTCAP('C')))
|
||||||
|
{
|
||||||
|
/* C buffer is empty. Start buffering by disabling access control */
|
||||||
|
|
||||||
|
modifyreg32(ABUFACCEN, ABUFACCEN_CDCEN('C'), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getreg32(ABUFACCEN) & ABUFACCEN_CDCEN('C'))
|
||||||
|
{
|
||||||
/* Enable C Buffer Under Level IRQ */
|
/* Enable C Buffer Under Level IRQ */
|
||||||
|
|
||||||
modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BULIRQEN('C'));
|
modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BULIRQEN('C'));
|
||||||
@ -636,17 +677,26 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
|||||||
/* Wait for Audio Buffer */
|
/* Wait for Audio Buffer */
|
||||||
|
|
||||||
_i2s_semtake(&_sem_buf_under);
|
_i2s_semtake(&_sem_buf_under);
|
||||||
|
}
|
||||||
volatile uint32_t *ptr = (uint32_t *)&apb->samp[apb->curbyte];
|
|
||||||
uint32_t n = apb->nbytes;
|
|
||||||
|
|
||||||
/* Setup and start DMA for I2S */
|
/* Setup and start DMA for I2S */
|
||||||
|
|
||||||
|
if (0 == (n % 4))
|
||||||
|
{
|
||||||
lc823450_dmasetup(_htxdma,
|
lc823450_dmasetup(_htxdma,
|
||||||
LC823450_DMA_SRCINC |
|
LC823450_DMA_SRCINC |
|
||||||
LC823450_DMA_SRCWIDTH_WORD |
|
LC823450_DMA_SRCWIDTH_WORD |
|
||||||
LC823450_DMA_DSTWIDTH_WORD,
|
LC823450_DMA_DSTWIDTH_WORD,
|
||||||
(uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n / 4);
|
(uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n / 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lc823450_dmasetup(_htxdma,
|
||||||
|
LC823450_DMA_SRCINC |
|
||||||
|
LC823450_DMA_SRCWIDTH_BYTE |
|
||||||
|
LC823450_DMA_DSTWIDTH_BYTE,
|
||||||
|
(uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n);
|
||||||
|
}
|
||||||
|
|
||||||
lc823450_dmastart(_htxdma,
|
lc823450_dmastart(_htxdma,
|
||||||
_i2s_txdma_callback,
|
_i2s_txdma_callback,
|
||||||
@ -654,9 +704,16 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
|||||||
|
|
||||||
_i2s_semtake(&_sem_txdma);
|
_i2s_semtake(&_sem_txdma);
|
||||||
|
|
||||||
/* Start C Buffer : TODO threshould */
|
#ifdef SHOW_BUFFERING
|
||||||
|
if (0 == (getreg32(ABUFACCEN) & ABUFACCEN_CDCEN('C')))
|
||||||
|
{
|
||||||
|
audinfo("buffering (remain=%d) \n", getreg32(BUF_DTCAP('C')));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (getreg32(BUF_DTCAP('C')) >= 1024)
|
/* Start C Buffer */
|
||||||
|
|
||||||
|
if (_i2s_tx_th_bytes < getreg32(BUF_DTCAP('C')))
|
||||||
{
|
{
|
||||||
modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('C'));
|
modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('C'));
|
||||||
}
|
}
|
||||||
@ -804,11 +861,11 @@ static int lc823450_i2s_configure(void)
|
|||||||
putreg32(MCLKCNTEXT3_AUDIOBUF_CLKEN,
|
putreg32(MCLKCNTEXT3_AUDIOBUF_CLKEN,
|
||||||
MCLKCNTEXT3);
|
MCLKCNTEXT3);
|
||||||
|
|
||||||
/* C Buffer : size=32KB, under level=1kB */
|
/* C Buffer : size=56KB, under level=1kB */
|
||||||
|
|
||||||
putreg32(base, BUF_BASE('C'));
|
putreg32(base, BUF_BASE('C'));
|
||||||
putreg32(4096 * 8, BUF_SIZE('C'));
|
putreg32(1024 * 56, BUF_SIZE('C'));
|
||||||
base += 4096 * 8;
|
base += 1024 * 56;
|
||||||
putreg32(1024, BUF_ULVL('C'));
|
putreg32(1024, BUF_ULVL('C'));
|
||||||
|
|
||||||
/* Setup F Buffer : size=512B */
|
/* Setup F Buffer : size=512B */
|
||||||
@ -894,6 +951,10 @@ static int lc823450_i2s_configure(void)
|
|||||||
audinfo("DTCAP(C)=0x%08x \n", BUF_DTCAP('C'));
|
audinfo("DTCAP(C)=0x%08x \n", BUF_DTCAP('C'));
|
||||||
audinfo("DTCAP(I)=0x%08x \n", BUF_DTCAP('I'));
|
audinfo("DTCAP(I)=0x%08x \n", BUF_DTCAP('I'));
|
||||||
audinfo("DTCAP(J)=0x%08x \n", BUF_DTCAP('J'));
|
audinfo("DTCAP(J)=0x%08x \n", BUF_DTCAP('J'));
|
||||||
|
|
||||||
|
/* Setup default tx threshold */
|
||||||
|
|
||||||
|
_setup_tx_threshold(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,3 +1044,12 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void)
|
|||||||
|
|
||||||
return &priv->dev;
|
return &priv->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_audio_bufcapacity
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
uint32_t up_audio_bufcapacity(void)
|
||||||
|
{
|
||||||
|
return (100 * getreg32(BUF_DTCAP('C'))) / getreg32(BUF_SIZE('C'));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user