mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-27 11:58:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			349 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * This file is specified for I2S standard communication mode
 | |
|  * Features:
 | |
|  *      - Philips/MSB/PCM are supported in standard mode
 | |
|  *      - Fixed to 2 slots
 | |
|  */
 | |
| #pragma once
 | |
| 
 | |
| #include "hal/i2s_types.h"
 | |
| #include "hal/gpio_types.h"
 | |
| #include "driver/i2s_common.h"
 | |
| 
 | |
| #include "sdkconfig.h"
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| #if CONFIG_IDF_TARGET_ESP32
 | |
| /**
 | |
|  * @brief Philips format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = true, \
 | |
|     .msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
 | |
|                 true : false, \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief PCM(short) format in 2 slots
 | |
|  * @note  PCM(long) is same as Philips in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)  { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = 1, \
 | |
|     .ws_pol = true, \
 | |
|     .bit_shift = true, \
 | |
|     .msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
 | |
|                 true : false, \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief MSB format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = false, \
 | |
|     .msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
 | |
|                 true : false, \
 | |
| }
 | |
| 
 | |
| #elif CONFIG_IDF_TARGET_ESP32S2
 | |
| /**
 | |
|  * @brief Philips format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = true, \
 | |
|     .msb_right = true, \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief PCM(short) format in 2 slots
 | |
|  * @note  PCM(long) is same as Philips in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)  { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = 1, \
 | |
|     .ws_pol = true, \
 | |
|     .bit_shift = true, \
 | |
|     .msb_right = true, \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief MSB format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
 | |
|                 I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = false, \
 | |
|     .msb_right = true, \
 | |
| }
 | |
| 
 | |
| #else
 | |
| /**
 | |
|  * @brief Philips format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = true, \
 | |
|     .left_align = true, \
 | |
|     .big_endian = false, \
 | |
|     .bit_order_lsb = false \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief PCM(short) format in 2 slots
 | |
|  * @note  PCM(long) is same as Philips in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)  { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = 1, \
 | |
|     .ws_pol = true, \
 | |
|     .bit_shift = true, \
 | |
|     .left_align = true, \
 | |
|     .big_endian = false, \
 | |
|     .bit_order_lsb = false \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief MSB format in 2 slots
 | |
|  * @param bits_per_sample I2S data bit width
 | |
|  * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
 | |
|  */
 | |
| #define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
 | |
|     .data_bit_width = bits_per_sample, \
 | |
|     .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
 | |
|     .slot_mode = mono_or_stereo, \
 | |
|     .slot_mask = I2S_STD_SLOT_BOTH, \
 | |
|     .ws_width = bits_per_sample, \
 | |
|     .ws_pol = false, \
 | |
|     .bit_shift = false, \
 | |
|     .left_align = true, \
 | |
|     .big_endian = false, \
 | |
|     .bit_order_lsb = false \
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /** @cond */
 | |
| #define I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) \
 | |
|         I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)  // Alias
 | |
| /** @endcond */
 | |
| 
 | |
| /**
 | |
|  * @brief I2S default standard clock configuration
 | |
|  * @note Please set the mclk_multiple to I2S_MCLK_MULTIPLE_384 while using 24 bits data width
 | |
|  *       Otherwise the sample rate might be imprecise since the BCLK division is not a integer
 | |
|  * @param rate sample rate
 | |
|  */
 | |
| #define I2S_STD_CLK_DEFAULT_CONFIG(rate) { \
 | |
|     .sample_rate_hz = rate, \
 | |
|     .clk_src = I2S_CLK_SRC_DEFAULT, \
 | |
|     .mclk_multiple = I2S_MCLK_MULTIPLE_256, \
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief I2S slot configuration for standard mode
 | |
|  */
 | |
| typedef struct {
 | |
|     /* General fields */
 | |
|     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
 | |
|                                                  *   In TX direction, mono means the written buffer contains only one slot data
 | |
|                                                  *   and stereo means the written buffer contains both left and right data
 | |
|                                                  */
 | |
| 
 | |
|     /* Particular fields */
 | |
|     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 to enable bit shift in Philips mode */
 | |
| #if SOC_I2S_HW_VERSION_1    // For esp32/esp32-s2
 | |
|     bool                    msb_right;          /*!< Set to place right channel data at the MSB in the FIFO */
 | |
| #else
 | |
|     bool                    left_align;         /*!< Set to enable left alignment */
 | |
|     bool                    big_endian;         /*!< Set to enable big endian */
 | |
|     bool                    bit_order_lsb;      /*!< Set to enable lsb first */
 | |
| #endif
 | |
| } i2s_std_slot_config_t;
 | |
| 
 | |
| /**
 | |
|  * @brief I2S clock configuration for standard mode
 | |
|  */
 | |
| typedef struct {
 | |
|     /* General fields */
 | |
|     uint32_t                sample_rate_hz;     /*!< I2S sample rate */
 | |
|     i2s_clock_src_t         clk_src;            /*!< Choose clock source, see `soc_periph_i2s_clk_src_t` for the supported clock sources.
 | |
|                                                  *   selected `I2S_CLK_SRC_EXTERNAL` (if supports) to enable the external source clock input via MCLK pin,
 | |
|                                                  */
 | |
| #if SOC_I2S_HW_VERSION_2
 | |
|     uint32_t                ext_clk_freq_hz;    /*!< External clock source frequency in Hz, only take effect when `clk_src = I2S_CLK_SRC_EXTERNAL`, otherwise this field will be ignored,
 | |
|                                                  *   Please make sure the frequency input is equal or greater than BCLK, i.e. `sample_rate_hz * slot_bits * 2`
 | |
|                                                  */
 | |
| #endif
 | |
|     i2s_mclk_multiple_t     mclk_multiple;      /*!< The multiple of MCLK to the sample rate
 | |
|                                                  *   Default is 256 in the helper macro, it can satisfy most of cases,
 | |
|                                                  *   but please set this field a multiple of `3` (like 384) when using 24-bit data width,
 | |
|                                                  *   otherwise the sample rate might be inaccurate
 | |
|                                                  */
 | |
| } i2s_std_clk_config_t;
 | |
| 
 | |
| /**
 | |
|  * @brief I2S standard mode GPIO pins configuration
 | |
|  */
 | |
| typedef struct {
 | |
|     gpio_num_t mclk;               /*!< MCK pin, output by default, input if the clock source is selected to `I2S_CLK_SRC_EXTERNAL` */
 | |
|     gpio_num_t bclk;               /*!< BCK pin, input in slave role, output in master role */
 | |
|     gpio_num_t ws;                 /*!< WS pin, input in slave role, output in master role */
 | |
|     gpio_num_t dout;               /*!< DATA pin, output */
 | |
|     gpio_num_t din;                /*!< DATA pin, input */
 | |
|     struct {
 | |
|         uint32_t   mclk_inv: 1;    /*!< Set 1 to invert the MCLK input/output */
 | |
|         uint32_t   bclk_inv: 1;    /*!< Set 1 to invert the BCLK input/output */
 | |
|         uint32_t   ws_inv: 1;      /*!< Set 1 to invert the WS input/output */
 | |
|     } invert_flags;                /*!< GPIO pin invert flags */
 | |
| } i2s_std_gpio_config_t;
 | |
| 
 | |
| /**
 | |
|  * @brief I2S standard mode major configuration that including clock/slot/GPIO configuration
 | |
|  */
 | |
| typedef struct {
 | |
|     i2s_std_clk_config_t    clk_cfg;    /*!< Standard mode clock configuration, can be generated by macro I2S_STD_CLK_DEFAULT_CONFIG */
 | |
|     i2s_std_slot_config_t   slot_cfg;   /*!< Standard mode slot configuration, can be generated by macros I2S_STD_[mode]_SLOT_DEFAULT_CONFIG, [mode] can be replaced with PHILIPS/MSB/PCM */
 | |
|     i2s_std_gpio_config_t   gpio_cfg;   /*!< Standard mode GPIO configuration, specified by user */
 | |
| } i2s_std_config_t;
 | |
| 
 | |
| /**
 | |
|  * @brief Initialize I2S channel to standard mode
 | |
|  * @note  Only allowed to be called when the channel state is REGISTERED, (i.e., channel has been allocated, but not initialized)
 | |
|  *        and the state will be updated to READY if initialization success, otherwise the state will return to REGISTERED.
 | |
|  *
 | |
|  * @param[in]   handle      I2S channel handler
 | |
|  * @param[in]   std_cfg     Configurations for standard mode, including clock, slot and GPIO
 | |
|  *                          The clock configuration can be generated by the helper macro `I2S_STD_CLK_DEFAULT_CONFIG`
 | |
|  *                          The slot configuration can be generated by the helper macro `I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`,
 | |
|  *                          `I2S_STD_PCM_SLOT_DEFAULT_CONFIG` or `I2S_STD_MSB_SLOT_DEFAULT_CONFIG`
 | |
|  *
 | |
|  * @return
 | |
|  *      - ESP_OK    Initialize successfully
 | |
|  *      - ESP_ERR_NO_MEM        No memory for storing the channel information
 | |
|  *      - ESP_ERR_INVALID_ARG   NULL pointer or invalid configuration
 | |
|  *      - ESP_ERR_INVALID_STATE This channel is not registered
 | |
|  */
 | |
| esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_config_t *std_cfg);
 | |
| 
 | |
| /**
 | |
|  * @brief Reconfigure the I2S clock for standard mode
 | |
|  * @note  Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
 | |
|  *        this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
 | |
|  * @note  The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
 | |
|  *
 | |
|  * @param[in]   handle      I2S channel handler
 | |
|  * @param[in]   clk_cfg     Standard mode clock configuration, can be generated by `I2S_STD_CLK_DEFAULT_CONFIG`
 | |
|  * @return
 | |
|  *      - ESP_OK    Set clock successfully
 | |
|  *      - ESP_ERR_INVALID_ARG   NULL pointer, invalid configuration or not standard mode
 | |
|  *      - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
 | |
|  */
 | |
| esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std_clk_config_t *clk_cfg);
 | |
| 
 | |
| /**
 | |
|  * @brief Reconfigure the I2S slot for standard mode
 | |
|  * @note  Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
 | |
|  *        this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
 | |
|  * @note  The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
 | |
|  *
 | |
|  * @param[in]   handle      I2S channel handler
 | |
|  * @param[in]   slot_cfg    Standard mode slot configuration, can be generated by `I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`,
 | |
|  *                          `I2S_STD_PCM_SLOT_DEFAULT_CONFIG` and `I2S_STD_MSB_SLOT_DEFAULT_CONFIG`.
 | |
|  * @return
 | |
|  *      - ESP_OK    Set clock successfully
 | |
|  *      - ESP_ERR_NO_MEM        No memory for DMA buffer
 | |
|  *      - ESP_ERR_INVALID_ARG   NULL pointer, invalid configuration  or not standard mode
 | |
|  *      - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
 | |
|  */
 | |
| esp_err_t i2s_channel_reconfig_std_slot(i2s_chan_handle_t handle, const i2s_std_slot_config_t *slot_cfg);
 | |
| 
 | |
| /**
 | |
|  * @brief Reconfigure the I2S GPIO for standard mode
 | |
|  * @note  Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
 | |
|  *        this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
 | |
|  * @note  The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
 | |
|  *
 | |
|  * @param[in]   handle      I2S channel handler
 | |
|  * @param[in]   gpio_cfg    Standard mode GPIO configuration, specified by user
 | |
|  * @return
 | |
|  *      - ESP_OK    Set clock successfully
 | |
|  *      - ESP_ERR_INVALID_ARG   NULL pointer, invalid configuration  or not standard mode
 | |
|  *      - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
 | |
|  */
 | |
| esp_err_t i2s_channel_reconfig_std_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_config_t *gpio_cfg);
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| }
 | |
| #endif
 | 
