esp32-sparrow-kit: Add I2S support for the board's microphone
The board's microphone uses 24-bit i2s and this commit also fixes the segmentation fault caused by the audio buffer overflow. arch/xtensa/src/esp32/esp32_i2s.c: Fix bug regarding 24-bit audio and add AUDIOIOC_STOP to ioctl drivers/audio/audio_i2s.c: Report number of channels on AUDIOIOC_GETCAPS in boards/xtensa/esp32/esp32-sparrow-kit: /configs/nsh/defconfig: Add I2S configs /src/esp32-sparrow-kit.h: Add the signature of esp32_i2sdev_initialize() /src/esp32_bringup.c: Add call to esp32_i2sdev_initialize() Signed-off-by: simonatoaca <simona.alexandra2000@gmail.com>
This commit is contained in:
parent
716a95934d
commit
bb6f32d610
@ -361,6 +361,7 @@ static void i2s_rx_channel_stop(struct esp32_i2s_s *priv);
|
|||||||
static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels);
|
static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels);
|
||||||
static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate);
|
static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate);
|
||||||
static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits);
|
static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits);
|
||||||
|
static void i2s_cleanup_queues(struct esp32_i2s_s *priv);
|
||||||
static int i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
static int i2s_receive(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);
|
||||||
@ -1304,6 +1305,7 @@ static void i2s_rx_worker(void *arg)
|
|||||||
|
|
||||||
apb_samp_t samp_size;
|
apb_samp_t samp_size;
|
||||||
uint32_t data_copied;
|
uint32_t data_copied;
|
||||||
|
uint8_t carry_bytes;
|
||||||
uint8_t padding;
|
uint8_t padding;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
uint8_t *samp;
|
uint8_t *samp;
|
||||||
@ -1322,23 +1324,48 @@ static void i2s_rx_worker(void *arg)
|
|||||||
samp = &bfcontainer->apb->samp[bfcontainer->apb->curbyte];
|
samp = &bfcontainer->apb->samp[bfcontainer->apb->curbyte];
|
||||||
samp_size = (bfcontainer->apb->nbytes - bfcontainer->apb->curbyte);
|
samp_size = (bfcontainer->apb->nbytes - bfcontainer->apb->curbyte);
|
||||||
|
|
||||||
|
data_copied = 0;
|
||||||
|
buf = bfcontainer->buf;
|
||||||
|
|
||||||
|
/* Copy the remaining bytes from previous transfer and
|
||||||
|
* complete the sample so that the next memcpy is aligned
|
||||||
|
* with the sample size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->rx.carry.bytes)
|
||||||
|
{
|
||||||
|
memcpy(samp, &priv->rx.carry.value, priv->rx.carry.bytes);
|
||||||
|
samp += priv->rx.carry.bytes;
|
||||||
|
data_copied += priv->rx.carry.bytes;
|
||||||
|
|
||||||
|
memcpy(samp, buf, (bytes_per_sample - priv->rx.carry.bytes));
|
||||||
|
buf += (bytes_per_sample - priv->rx.carry.bytes);
|
||||||
|
samp += (bytes_per_sample - priv->rx.carry.bytes);
|
||||||
|
data_copied += (bytes_per_sample - priv->rx.carry.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is no need to add padding bytes, the memcpy may be done at
|
/* If there is no need to add padding bytes, the memcpy may be done at
|
||||||
* once. Otherwise, the operation must add the padding bytes to each
|
* once. Otherwise, the operation must add the padding bytes to each
|
||||||
* sample in the internal buffer.
|
* sample in the internal buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
data_copied = 0;
|
buf += padding;
|
||||||
buf = bfcontainer->buf + padding;
|
|
||||||
|
|
||||||
if (padding)
|
if (padding)
|
||||||
{
|
{
|
||||||
while (data_copied < samp_size)
|
while (data_copied + bytes_per_sample <= samp_size)
|
||||||
{
|
{
|
||||||
memcpy(samp, buf, bytes_per_sample);
|
memcpy(samp, buf, bytes_per_sample);
|
||||||
buf += (bytes_per_sample + padding);
|
buf += (bytes_per_sample + padding);
|
||||||
samp += bytes_per_sample;
|
samp += bytes_per_sample;
|
||||||
data_copied += bytes_per_sample;
|
data_copied += bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store the carry bytes, if any */
|
||||||
|
|
||||||
|
carry_bytes = samp_size - data_copied;
|
||||||
|
memcpy(&priv->rx.carry.value, buf, carry_bytes);
|
||||||
|
priv->rx.carry.bytes = carry_bytes;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2815,6 +2842,56 @@ errout_with_buf:
|
|||||||
}
|
}
|
||||||
#endif /* I2S_HAVE_RX */
|
#endif /* I2S_HAVE_RX */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: i2s_cleanup_queues
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Wait for all buffers to be processed and free them after
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef I2S_HAVE_RX
|
||||||
|
static void i2s_cleanup_queues(struct esp32_i2s_s *priv)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
struct esp32_buffer_s *bfcontainer;
|
||||||
|
|
||||||
|
while (sq_peek(&priv->rx.done) != NULL)
|
||||||
|
{
|
||||||
|
flags = enter_critical_section();
|
||||||
|
bfcontainer = (struct esp32_buffer_s *)sq_remfirst(&priv->rx.done);
|
||||||
|
leave_critical_section(flags);
|
||||||
|
bfcontainer->callback(&priv->dev, bfcontainer->apb,
|
||||||
|
bfcontainer->arg, OK);
|
||||||
|
apb_free(bfcontainer->apb);
|
||||||
|
i2s_buf_free(priv, bfcontainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sq_peek(&priv->rx.act) != NULL)
|
||||||
|
{
|
||||||
|
flags = enter_critical_section();
|
||||||
|
bfcontainer = (struct esp32_buffer_s *)sq_remfirst(&priv->rx.act);
|
||||||
|
leave_critical_section(flags);
|
||||||
|
bfcontainer->callback(&priv->dev, bfcontainer->apb,
|
||||||
|
bfcontainer->arg, OK);
|
||||||
|
apb_free(bfcontainer->apb);
|
||||||
|
i2s_buf_free(priv, bfcontainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sq_peek(&priv->rx.pend) != NULL)
|
||||||
|
{
|
||||||
|
flags = enter_critical_section();
|
||||||
|
bfcontainer = (struct esp32_buffer_s *)sq_remfirst(&priv->rx.pend);
|
||||||
|
leave_critical_section(flags);
|
||||||
|
bfcontainer->apb->flags |= AUDIO_APB_FINAL;
|
||||||
|
bfcontainer->callback(&priv->dev, bfcontainer->apb,
|
||||||
|
bfcontainer->arg, OK);
|
||||||
|
apb_free(bfcontainer->apb);
|
||||||
|
i2s_buf_free(priv, bfcontainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* I2S_HAVE_RX */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: i2s_ioctl
|
* Name: i2s_ioctl
|
||||||
*
|
*
|
||||||
@ -2843,6 +2920,25 @@ static int i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* AUDIOIOC_STOP - Stop the audio stream.
|
||||||
|
*
|
||||||
|
* ioctl argument: Audio session
|
||||||
|
*/
|
||||||
|
|
||||||
|
case AUDIOIOC_STOP:
|
||||||
|
{
|
||||||
|
i2sinfo("AUDIOIOC_STOP\n");
|
||||||
|
|
||||||
|
#ifdef I2S_HAVE_RX
|
||||||
|
struct esp32_i2s_s *priv = (struct esp32_i2s_s *)dev;
|
||||||
|
|
||||||
|
i2s_cleanup_queues(priv);
|
||||||
|
#endif /* I2S_HAVE_RX */
|
||||||
|
|
||||||
|
ret = OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer
|
/* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer
|
||||||
*
|
*
|
||||||
* ioctl argument: pointer to an audio_buf_desc_s structure
|
* ioctl argument: pointer to an audio_buf_desc_s structure
|
||||||
|
@ -22,12 +22,26 @@ CONFIG_ARCH_CHIP_ESP32=y
|
|||||||
CONFIG_ARCH_CHIP_ESP32WROVER=y
|
CONFIG_ARCH_CHIP_ESP32WROVER=y
|
||||||
CONFIG_ARCH_STACKDUMP=y
|
CONFIG_ARCH_STACKDUMP=y
|
||||||
CONFIG_ARCH_XTENSA=y
|
CONFIG_ARCH_XTENSA=y
|
||||||
|
CONFIG_AUDIO=y
|
||||||
|
CONFIG_AUDIO_DMA=y
|
||||||
|
CONFIG_AUDIO_FORMAT_RAW=y
|
||||||
|
CONFIG_AUDIO_I2S=y
|
||||||
CONFIG_BME680_ENABLE_IIR_FILTER=y
|
CONFIG_BME680_ENABLE_IIR_FILTER=y
|
||||||
CONFIG_BOARD_LOOPSPERMSEC=16717
|
CONFIG_BOARD_LOOPSPERMSEC=16717
|
||||||
CONFIG_BUILTIN=y
|
CONFIG_BUILTIN=y
|
||||||
|
CONFIG_DMA=y
|
||||||
|
CONFIG_DMA_LINK=y
|
||||||
|
CONFIG_DRIVERS_AUDIO=y
|
||||||
CONFIG_DRIVERS_VIDEO=y
|
CONFIG_DRIVERS_VIDEO=y
|
||||||
CONFIG_ESP32_I2C0=y
|
CONFIG_ESP32_I2C0=y
|
||||||
CONFIG_ESP32_I2C0_SDAPIN=21
|
CONFIG_ESP32_I2C0_SDAPIN=21
|
||||||
|
CONFIG_ESP32_I2S0=y
|
||||||
|
CONFIG_ESP32_I2S0_BCLKPIN=25
|
||||||
|
CONFIG_ESP32_I2S0_DATA_BIT_WIDTH_24BIT=y
|
||||||
|
CONFIG_ESP32_I2S0_DINPIN=26
|
||||||
|
CONFIG_ESP32_I2S0_SAMPLE_RATE=8000
|
||||||
|
CONFIG_ESP32_I2S0_WSPIN=27
|
||||||
|
CONFIG_ESP32_I2S=y
|
||||||
CONFIG_ESP32_LEDC=y
|
CONFIG_ESP32_LEDC=y
|
||||||
CONFIG_ESP32_LEDC_CHANNEL0_PIN=14
|
CONFIG_ESP32_LEDC_CHANNEL0_PIN=14
|
||||||
CONFIG_ESP32_LEDC_CHANNEL1_PIN=13
|
CONFIG_ESP32_LEDC_CHANNEL1_PIN=13
|
||||||
@ -47,6 +61,7 @@ CONFIG_FS_FAT=y
|
|||||||
CONFIG_FS_PROCFS=y
|
CONFIG_FS_PROCFS=y
|
||||||
CONFIG_HAVE_CXX=y
|
CONFIG_HAVE_CXX=y
|
||||||
CONFIG_HAVE_CXXINITIALIZE=y
|
CONFIG_HAVE_CXXINITIALIZE=y
|
||||||
|
CONFIG_I2S_DMADESC_NUM=4
|
||||||
CONFIG_IDLETHREAD_STACKSIZE=3072
|
CONFIG_IDLETHREAD_STACKSIZE=3072
|
||||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||||
CONFIG_INTELHEX_BINARY=y
|
CONFIG_INTELHEX_BINARY=y
|
||||||
@ -75,6 +90,7 @@ CONFIG_RGBLED_INVERT=y
|
|||||||
CONFIG_RGBLED_LIGHTNESS_CORRECTION=y
|
CONFIG_RGBLED_LIGHTNESS_CORRECTION=y
|
||||||
CONFIG_RGBLED_PWM_FREQ=200
|
CONFIG_RGBLED_PWM_FREQ=200
|
||||||
CONFIG_RR_INTERVAL=200
|
CONFIG_RR_INTERVAL=200
|
||||||
|
CONFIG_SCHED_HPWORK=y
|
||||||
CONFIG_SCHED_WAITPID=y
|
CONFIG_SCHED_WAITPID=y
|
||||||
CONFIG_SENSORS=y
|
CONFIG_SENSORS=y
|
||||||
CONFIG_SENSORS_BME680=y
|
CONFIG_SENSORS_BME680=y
|
||||||
|
@ -106,6 +106,28 @@ int esp32_mmcsd_initialize(int minor);
|
|||||||
|
|
||||||
int esp32_spiflash_init(void);
|
int esp32_spiflash_init(void);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: board_i2sdev_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called by platform-specific, setup logic to configure
|
||||||
|
* and register the generic I2S audio driver. This function will register
|
||||||
|
* the driver as /dev/audio/pcm[x] where x is determined by the I2S port
|
||||||
|
* number.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* port - The I2S port used for the device
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero is returned on success. Otherwise, a negated errno value is
|
||||||
|
* returned to indicate the nature of the failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if defined CONFIG_ESP32_I2S0 || defined CONFIG_ESP32_I2S1
|
||||||
|
int board_i2sdev_initialize(int port);
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: esp32_gpio_init
|
* Name: esp32_gpio_init
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -80,6 +80,10 @@
|
|||||||
# include "esp32_board_i2c.h"
|
# include "esp32_board_i2c.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32_I2S
|
||||||
|
# include "esp32_i2s.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SENSORS_BMP180
|
#ifdef CONFIG_SENSORS_BMP180
|
||||||
# include "esp32_bmp180.h"
|
# include "esp32_bmp180.h"
|
||||||
#endif
|
#endif
|
||||||
@ -343,6 +347,23 @@ int esp32_bringup(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32_I2S
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32_I2S0
|
||||||
|
|
||||||
|
/* Configure I2S generic audio on I2S0 */
|
||||||
|
|
||||||
|
ret = board_i2sdev_initialize(ESP32_I2S0);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "Failed to initialize I2S%d driver: %d\n",
|
||||||
|
CONFIG_ESP32_I2S0, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP32_I2S0 */
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP32_I2S */
|
||||||
|
|
||||||
#ifdef CONFIG_SENSORS_BMP180
|
#ifdef CONFIG_SENSORS_BMP180
|
||||||
/* Try to register BMP180 device in I2C0 */
|
/* Try to register BMP180 device in I2C0 */
|
||||||
|
|
||||||
|
@ -185,6 +185,9 @@ static int audio_i2s_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||||||
/* Report the Sample rates we support */
|
/* Report the Sample rates we support */
|
||||||
|
|
||||||
caps->ac_controls.hw[0] = AUDIO_SAMP_RATE_DEF_ALL;
|
caps->ac_controls.hw[0] = AUDIO_SAMP_RATE_DEF_ALL;
|
||||||
|
|
||||||
|
caps->ac_channels = 2;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user