Low Power Inter-IC Sound (LP I2S)

Introduction

LP I2S (Low Power Inter-IC Sound) is a synchronous protocol which can be used for audio data transmission. It also provides a data reception communication interface for Voice Activity Detection (VAD) and some digital audio applications in low power mode. For more details about VAD, see Voice Activity Detection.

Note

For I2S documentation, see Inter-IC Sound.

The I2S standard bus defines three signals, - BCK: bit clock - WS: word select - SD: serial data

A basic I2S data bus has one master and one slave. The roles remain unchanged throughout the communication.

LP I2S on ESP32-P4 only supports working as an I2S Slave.

The LP I2S module on ESP32-P4 provides an independent RX unit, which supports receiving data when the chip is running under sleep modes. Compared to HP I2S, LP I2S does not support DMA access. Instead, it uses a piece of separate internal memory to store data.

I2S Communication Mode

Standard Mode

In standard mode, there are always two sound channels, i.e., the left and right channels, which are called "slots". These slots support 16-bit-width sample data. The communication format for the slots can be found in this I2S Communication Mode section.

PDM Mode (RX)

PDM (Pulse-density Modulation) mode for RX channel can receive PDM-format data. Only 16-bit-width sample data are supported. The communication format for the slots can be found in this I2S Communication Mode section.

Functional Overview

Resource Allocation

To create a LP I2S channel handle, you should set up the LP I2S channel configuration structure lp_i2s_chan_config_t, and call lp_i2s_new_channel() with the prepared configuration structure.

If the LP I2S channel is no longer used, you should recycle the allocated resource by calling lp_i2s_del_channel().

//initialization
lp_i2s_chan_handle_t rx_handle = NULL;
lp_i2s_chan_config_t config = {
    .id = 0,
    .role = I2S_ROLE_SLAVE,
    .threshold = 512,
};
ESP_ERROR_CHECK(lp_i2s_new_channel(&config, NULL, &rx_handle));

//deinitialization
ESP_ERROR_CHECK(lp_i2s_del_channel(rx_chan));

Register Event Callbacks

By calling lp_i2s_register_event_callbacks(), you can hook your own function to the driver ISR. Supported event callbacks are listed in lp_i2s_evt_cbs_t.

As the above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logic should not appear in these callbacks. The callback function prototype is declared in lp_i2s_callback_t.

You can also register your own context when calling lp_i2s_register_event_callbacks() by the parameter user_data. This user data will be passed to the callback functions directly.

This function may fail due to reasons like ESP_ERR_INVALID_ARG, especially, this error may indicate that the callback functions are not in the internal RAM. Callbacks should be placed in IRAM since the default ISR handler is allocated with the ESP_INTR_FLAG_IRAM flag.

Please check the error log for more details. If it fails due to ESP_ERR_INVALID_STATE, it indicates that the LP I2S channel is enabled, and you cannot add a callback at this moment.

lp_i2s_evt_cbs_t cbs = {
        .on_thresh_met = s_lp_i2s_on_thresh_met,
        .on_request_new_trans = s_lp_i2s_on_request_new_trans,
};
ESP_ERROR_CHECK(lp_i2s_register_event_callbacks(rx_chan, &cbs, &trans));

Enable and Disable LP I2S

Before using LP I2S to receive data, you need to enable the LP I2S channel by calling lp_i2s_channel_enable(), this function switches the driver state from init to enable. Calling lp_i2s_channel_disable() does the opposite, that is, puts the driver back to the init state.

Communication Mode

Read Data via LP I2S

After the LP I2S channel is enabled, lp_i2s_channel_read() and lp_i2s_channel_read_until_bytes() will be available.

Thread Safety

All the APIs are guaranteed to be thread safe by the driver, which means, you can call them from different RTOS tasks without protection by extra locks.

All the APIs are not allowed to be used in ISR context.

API Reference

Header File

  • components/esp_driver_i2s/include/driver/lp_i2s.h

  • This header file can be included with:

    #include "driver/lp_i2s.h"
    
  • This header file is a part of the API provided by the esp_driver_i2s component. To declare that your component depends on esp_driver_i2s, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_i2s
    

    or

    PRIV_REQUIRES esp_driver_i2s
    

Functions

esp_err_t lp_i2s_new_channel(const lp_i2s_chan_config_t *chan_cfg, lp_i2s_chan_handle_t *ret_tx_handle, lp_i2s_chan_handle_t *ret_rx_handle)

Allocate new LP I2S channel(s)

Parameters
  • chan_cfg -- [in] LP I2S controller channel configurations

  • ret_tx_handle -- [out] LP I2S channel handler used for managing the sending channel(optional), this one is not supported and is kept here for future-proof.

  • ret_rx_handle -- [out] LP I2S channel handler used for managing the receiving channel(optional)

Returns

  • ESP_OK Allocate new channel(s) success

  • ESP_ERR_NOT_SUPPORTED The communication mode is not supported on the current chip

  • ESP_ERR_INVALID_ARG NULL pointer or illegal parameter in lp_i2s_chan_config_t

  • ESP_ERR_NOT_FOUND No available LP I2S channel found

esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t chan, const lp_i2s_evt_cbs_t *cbs, void *user_data)

Register LP I2S event callbacks.

Parameters
  • chan -- [in] LP I2S channel handle

  • cbs -- [in] Callbacks

  • user_data -- [in] User data

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state

esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan)

Enable LP I2S driver.

Parameters

chan -- [in] LP I2S channel handle

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state

esp_err_t lp_i2s_channel_read(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans, uint32_t timeout_ms)

Read LP I2S received data.

Parameters
  • chan -- [in] LP I2S channel handle

  • trans -- [in] LP I2S transaction

  • timeout_ms -- [in] Timeout in ms, set to LP_I2S_MAX_DELAY to wait until read is done

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state, e.g. on_request_new_trans callback is registered

esp_err_t lp_i2s_channel_read_until_bytes(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans)

Read LP I2S received data until certain bytes.

Parameters
  • chan -- [in] LP I2S channel handle

  • trans -- [in] LP I2S transaction

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state, e.g. on_request_new_trans callback is registered

esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan)

Disable LP I2S driver.

Parameters

chan -- [in] LP I2S channel handle

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state

esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan)

Delete the LP I2S channel.

Parameters

chan -- [in] LP I2S channel handler

Returns

  • ESP_OK Delete successfully

  • ESP_ERR_INVALID_ARG NULL pointer

Structures

struct lp_i2s_chan_config_t

LP I2S controller channel configuration.

Public Members

int id

LP I2S port id

i2s_role_t role

LP I2S role, only I2S_ROLE_SLAVE supported

size_t threshold

When LP I2S received bytes are bigger than this value, the on_thresh_met callback will be triggered. Must be in multiple of 4

struct lp_i2s_evt_cbs_t

LP I2S event callbacks.

Public Members

lp_i2s_callback_t on_thresh_met

Triggered when the received bytes are bigger than lp_i2s_chan_config_t:threshold

lp_i2s_callback_t on_request_new_trans

Triggered when a new transaction buffer is needed, when this callback is registered, you don't need to use lp_i2s_channel_read to get data, you can get data via this callback asynchronously.

Macros

LP_I2S_MAX_DELAY

LP_I2S max timeout value.

Header File

  • components/esp_driver_i2s/include/driver/lp_i2s_std.h

  • This header file can be included with:

    #include "driver/lp_i2s_std.h"
    
  • This header file is a part of the API provided by the esp_driver_i2s component. To declare that your component depends on esp_driver_i2s, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_i2s
    

    or

    PRIV_REQUIRES esp_driver_i2s
    

Functions

esp_err_t lp_i2s_channel_init_std_mode(lp_i2s_chan_handle_t handle, const lp_i2s_std_config_t *std_cfg)

Init LP I2S to STD mode.

Parameters
  • handle -- [in] LP I2S channel handle

  • std_cfg -- [in] STD configuration

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state

Structures

struct lp_i2s_std_gpio_config_t

LP I2S pin configurations.

Public Members

int bck

bck pin number

int ws

ws pin number

int din

din pin number

struct lp_i2s_std_slot_config_t

LP I2S slot configuration for standard mode.

Public Members

i2s_data_bit_width_t data_bit_width

I2S sample data bit width (valid data bits per sample)

i2s_slot_bit_width_t slot_bit_width

I2S slot bit width (total bits per slot)

i2s_slot_mode_t slot_mode

Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO

i2s_std_slot_mask_t slot_mask

Select the left, right or both slot

uint32_t ws_width

WS signal width (i.e. the number of BCLK ticks that WS signal is high)

bool ws_pol

WS signal polarity, set true to enable high lever first

bool bit_shift

Set true to enable bit shift in Philips mode

bool left_align

Set true to enable left alignment

bool big_endian

Set true to enable big endian

bool bit_order_lsb

Set true to enable lsb first

struct lp_i2s_std_config_t

LP I2S STD configuration.

Public Members

lp_i2s_std_gpio_config_t pin_cfg

Pin configuration

lp_i2s_std_slot_config_t slot_cfg

STD mode slot configuration, can be generated by macros I2S_STD_[mode]_SLOT_DEFAULT_CONFIG, [mode] can be replaced with PHILIPS/MSB/PCM_SHORT/PCM_LONG

Macros

LP_I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)

Philips format in active slot that enabled by mask.

Parameters
  • bits_per_sample -- I2S data bit width

  • mono_or_stereo -- I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO

LP_I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)

MSB format in active slot enabled that by mask.

Parameters
  • bits_per_sample -- I2S data bit width

  • mono_or_stereo -- I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO

LP_I2S_STD_PCM_SHORT_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)

PCM(short) format in active slot that enabled by mask.

Parameters
  • bits_per_sample -- I2S data bit width

  • mono_or_stereo -- I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO

Header File

  • components/esp_driver_i2s/include/driver/lp_i2s_pdm.h

  • This header file can be included with:

    #include "driver/lp_i2s_pdm.h"
    
  • This header file is a part of the API provided by the esp_driver_i2s component. To declare that your component depends on esp_driver_i2s, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_i2s
    

    or

    PRIV_REQUIRES esp_driver_i2s
    

Functions

esp_err_t lp_i2s_channel_init_pdm_rx_mode(lp_i2s_chan_handle_t handle, const lp_i2s_pdm_rx_config_t *pdm_cfg)

Init LP I2S to PDM mode.

Parameters
  • handle -- [in] LP I2S channel handle

  • pdm_cfg -- [in] PDM configuration

Returns

  • ESP_OK: On success

  • ESP_ERR_INVALID_ARG: Invalid argument

  • ESP_ERR_INVALID_STATE: Invalid state

Structures

struct lp_i2s_pdm_rx_gpio_config_t

LP I2S pin configurations.

Public Members

int clk

clk pin number

int din

din pin number

struct lp_i2s_pdm_rx_slot_config_t

I2S slot configuration for PDM RX mode.

Public Members

i2s_data_bit_width_t data_bit_width

I2S sample data bit width (valid data bits per sample), only support 16 bits for PDM mode

i2s_slot_bit_width_t slot_bit_width

I2S slot bit width (total bits per slot) , only support 16 bits for PDM mode

i2s_slot_mode_t slot_mode

Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO

i2s_pdm_slot_mask_t slot_mask

Choose the slots to activate

bool ws_pol

WS signal polarity, set true to enable high lever first

bool hp_en

High pass filter enable

float hp_cut_off_freq_hz

High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above

uint32_t amplify_num

The amplification number of the final conversion result. The data that have converted from PDM to PCM module, will time amplify_num additionally to amplify the final result. Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal range 1~15, default 1

struct lp_i2s_pdm_rx_config_t

LP I2S PDM configuration.

Public Members

lp_i2s_pdm_rx_gpio_config_t pin_cfg

Pin configuration

lp_i2s_pdm_rx_slot_config_t slot_cfg

PDM mode slot configuration

Macros

LP_I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)

PDM format in 2 slots(RX)

Parameters
  • bits_per_sample -- I2S data bit width, only support 16 bits for PDM mode

  • mono_or_stereo -- I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO


Was this page helpful?