mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 02:37:19 +02:00
doc(lp_i2s): lp i2s programming guide
This commit is contained in:
@ -55,7 +55,7 @@ esp_err_t lp_i2s_new_channel(const lp_i2s_chan_config_t *chan_cfg, lp_i2s_chan_h
|
||||
/**
|
||||
* @brief Register LP I2S event callbacks
|
||||
*
|
||||
* @param[in] handle LP I2S channel handle
|
||||
* @param[in] chan LP I2S channel handle
|
||||
* @param[in] cbs Callbacks
|
||||
* @param[in] user_data User data
|
||||
*
|
||||
@ -64,12 +64,12 @@ esp_err_t lp_i2s_new_channel(const lp_i2s_chan_config_t *chan_cfg, lp_i2s_chan_h
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t handle, const lp_i2s_evt_cbs_t *cbs, void *user_data);
|
||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t chan, const lp_i2s_evt_cbs_t *cbs, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Enable LP I2S driver
|
||||
*
|
||||
* @param[in] handle LP I2S channel handle
|
||||
* @param[in] chan LP I2S channel handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
@ -81,7 +81,7 @@ esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan);
|
||||
/**
|
||||
* @brief Read LP I2S received data
|
||||
*
|
||||
* @param[in] handle LP I2S channel handle
|
||||
* @param[in] chan LP I2S channel handle
|
||||
* @param[in] trans LP I2S transaction
|
||||
* @param[in] timeout_ms Timeout in ms, set to `LP_I2S_MAX_DELAY` to wait until read is done
|
||||
*
|
||||
@ -95,7 +95,7 @@ esp_err_t lp_i2s_channel_read(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans,
|
||||
/**
|
||||
* @brief Read LP I2S received data until certain bytes
|
||||
*
|
||||
* @param[in] handle LP I2S channel handle
|
||||
* @param[in] chan LP I2S channel handle
|
||||
* @param[in] trans LP I2S transaction
|
||||
*
|
||||
* @return
|
||||
@ -108,7 +108,7 @@ esp_err_t lp_i2s_channel_read_until_bytes(lp_i2s_chan_handle_t chan, lp_i2s_tran
|
||||
/**
|
||||
* @brief Disable LP I2S driver
|
||||
*
|
||||
* @param[in] handle LP I2S channel handle
|
||||
* @param[in] chan LP I2S channel handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
@ -120,13 +120,13 @@ esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan);
|
||||
/**
|
||||
* @brief Delete the LP I2S channel
|
||||
*
|
||||
* @param[in] handle LP I2S channel handler
|
||||
* @param[in] chan LP I2S channel handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Delete successfully
|
||||
* - ESP_ERR_INVALID_ARG NULL pointer
|
||||
*/
|
||||
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t handle);
|
||||
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -246,10 +246,10 @@ esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan)
|
||||
_Static_assert(sizeof(lp_i2s_evt_cbs_t) == sizeof(lp_i2s_evt_cbs_internal_t), "Invalid size of lp_i2s_evt_cbs_t structure");
|
||||
#endif
|
||||
|
||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t handle, const lp_i2s_evt_cbs_t *cbs, void *user_data)
|
||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t chan, const lp_i2s_evt_cbs_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(handle->state < I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel is in enabled state already");
|
||||
ESP_RETURN_ON_FALSE(chan && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(chan->state < I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel is in enabled state already");
|
||||
|
||||
if (cbs->on_thresh_met) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_thresh_met), ESP_ERR_INVALID_ARG, TAG, "on_thresh_met callback not in IRAM");
|
||||
@ -258,9 +258,9 @@ esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t handle, const lp_
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_request_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_request_new_trans callback not in IRAM");
|
||||
}
|
||||
|
||||
handle->cbs.on_thresh_met = cbs->on_thresh_met;
|
||||
handle->cbs.on_request_new_trans = cbs->on_request_new_trans;
|
||||
handle->user_data = user_data;
|
||||
chan->cbs.on_thresh_met = cbs->on_thresh_met;
|
||||
chan->cbs.on_request_new_trans = cbs->on_request_new_trans;
|
||||
chan->user_data = user_data;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -125,6 +125,9 @@ INPUT = \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/i2s_pdm.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/i2s_std.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/i2s_tdm.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s_std.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s_pdm.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/i2s_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_pcnt/include/driver/pulse_cnt.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_rmt/include/driver/rmt_common.h \
|
||||
|
@ -10,6 +10,12 @@ Introduction
|
||||
|
||||
I2S (Inter-IC Sound) is a synchronous serial communication protocol usually used for transmitting audio data between two digital audio devices.
|
||||
|
||||
.. only:: SOC_LP_I2S_SUPPORTED
|
||||
|
||||
.. note::
|
||||
|
||||
For LP I2S documentation, see :doc:`Low Power Inter-IC Sound <./lp_i2s>`.
|
||||
|
||||
{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
|
||||
|
||||
An I2S bus that communicates in standard or TDM mode consists of the following lines:
|
||||
|
@ -41,6 +41,7 @@ Peripherals API
|
||||
:SOC_GPSPI_SUPPORTED: spi_master
|
||||
:SOC_GPSPI_SUPPORTED: spi_slave
|
||||
:SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd
|
||||
:SOC_LP_I2S_SUPPORTED: lp_i2s
|
||||
:SOC_TEMP_SENSOR_SUPPORTED: temp_sensor
|
||||
:SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad
|
||||
:esp32p4: cap_touch_sens
|
||||
|
147
docs/en/api-reference/peripherals/lp_i2s.rst
Normal file
147
docs/en/api-reference/peripherals/lp_i2s.rst
Normal file
@ -0,0 +1,147 @@
|
||||
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 :doc:`Voice Activity Detection <./vad>`.
|
||||
|
||||
.. only:: SOC_I2S_SUPPORTED
|
||||
|
||||
.. note::
|
||||
|
||||
For I2S documentation, see :doc:`Inter-IC Sound <./i2s>`.
|
||||
|
||||
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.
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
LP I2S on {IDF_TARGET_NAME} only supports working as an I2S Slave.
|
||||
|
||||
The LP I2S module on {IDF_TARGET_NAME} provides an independent RX unit, which supports receiving data when the chip is running with the lowest power consumption. 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 mainly includes the following:
|
||||
|
||||
- **Philips Format**: Data signal has one-bit shift comparing to the WS signal, and the duty of WS signal is 50%.
|
||||
|
||||
.. wavedrom:: /../_static/diagrams/i2s/std_philips.json
|
||||
|
||||
- **MSB Format**: Basically the same as Philips format, but without data shift.
|
||||
|
||||
.. wavedrom:: /../_static/diagrams/i2s/std_msb.json
|
||||
|
||||
- **PCM Short Format**: Data has one-bit shift and meanwhile the WS signal becomes a pulse lasting for one BCLK cycle.
|
||||
|
||||
.. wavedrom:: /../_static/diagrams/i2s/std_pcm.json
|
||||
|
||||
PDM Mode (RX)
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
PDM (Pulse-density Modulation) mode for RX channel can receive PDM-format data. Only 16-bit-width sample data are supported.
|
||||
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
Resource Allocation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To create a LP I2S channel handle, you should set up the LP I2S channel configuration structure :cpp:type:`lp_i2s_chan_config_t`, and call :cpp:func:`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 :cpp:func:`lp_i2s_del_channel`.
|
||||
|
||||
.. code:: c
|
||||
|
||||
//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 :cpp:func:`lp_i2s_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`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 :cpp:type:`lp_i2s_callback_t`.
|
||||
|
||||
You can also register your own context when calling :cpp:func:`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 :c:macro:`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 :c:macro:`ESP_ERR_INVALID_STATE`, it indicates that the LP I2S channel is enabled, and you cannot add a callback at this moment.
|
||||
|
||||
.. code:: c
|
||||
|
||||
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 :cpp:func:`lp_i2s_channel_enable`, this function switches the driver state from **init** to **enable**. Calling :cpp:func:`lp_i2s_channel_disable` does the opposite, that is, puts the driver back to the **init** state.
|
||||
|
||||
Communication Mode
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. list::
|
||||
|
||||
- Calling :cpp:func:`lp_i2s_channel_init_std_mode` can help you initialize the LP I2S channel to STD mode. Some initialization helpers are listed below:
|
||||
- :c:macro:`LP_I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`
|
||||
- :c:macro:`LP_I2S_STD_MSB_SLOT_DEFAULT_CONFIG`
|
||||
- :c:macro:`LP_I2S_STD_PCM_SHORT_SLOT_DEFAULT_CONFIG`
|
||||
|
||||
- Calling :cpp:func:`lp_i2s_channel_init_pdm_rx_mode` can help you initialize the LP I2S channel to PDM mode. :c:macro:`LP_I2S_PDM_RX_SLOT_DEFAULT_CONFIG` is an initialization helper.
|
||||
|
||||
Read Data via LP I2S
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After the LP I2S channel is enabled, :cpp:func:`lp_i2s_channel_read` and :cpp:func:`lp_i2s_channel_read_until_bytes` will be available.
|
||||
|
||||
.. list::
|
||||
|
||||
- For :cpp:func:`lp_i2s_channel_read`, if there are new data received by the LP I2S channel, this API will move the received data to the ``buffer`` you specified in :cpp:type:`lp_i2s_trans_t`. The API will try to receive the data as the ``buflen`` you specified. Check the ``received_size`` to know how many bytes you received, in case there are no enough received data. If no new received data, the API will block until ``timeout_ms``.
|
||||
|
||||
- For :cpp:func:`lp_i2s_channel_read_until_bytes`, this API is a wrapper of the :cpp:func:`lp_i2s_channel_read`. The difference is, the :cpp:func:`lp_i2s_channel_read_until_bytes` will block until ``buflen`` bytes are received.
|
||||
|
||||
- For both of the two APIs, if :cpp:member:`lp_i2s_evt_cbs_t::on_request_new_trans` is set, the driver will each time requesting a new LP I2S transaction descriptor (:cpp:type:`lp_i2s_trans_t`) from the callback event data structure (:cpp:type:`lp_i2s_evt_data_t`). This also means, the ``buffer`` in the (:cpp:type:`lp_i2s_trans_t`) needs to be ready for receiving data.
|
||||
|
||||
|
||||
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
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/lp_i2s.inc
|
||||
.. include-build-file:: inc/lp_i2s_std.inc
|
||||
.. include-build-file:: inc/lp_i2s_pdm.inc
|
||||
.. include-build-file:: inc/components/esp_driver_i2s/include/driver/i2s_types.inc
|
Reference in New Issue
Block a user