2021-08-18 07:45:51 -04:00
/*
2024-04-02 02:57:00 -04:00
* SPDX - FileCopyrightText : 2022 - 2024 Espressif Systems ( Shanghai ) CO LTD
2021-08-18 07:45:51 -04:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
# pragma once
# include "freertos/FreeRTOS.h"
2023-09-11 03:09:31 -04:00
# include "freertos/semphr.h"
# include "freertos/queue.h"
2021-08-18 07:45:51 -04:00
# include "soc/lldesc.h"
# include "soc/soc_caps.h"
2023-09-07 04:47:26 -04:00
# include "hal/i2s_hal.h"
2024-07-03 03:39:23 -04:00
# include "hal/lp_i2s_hal.h"
# if SOC_LP_I2S_SUPPORTED
# include "hal/lp_i2s_ll.h"
# endif
2022-04-07 03:32:46 -04:00
# include "driver/i2s_types.h"
2023-09-11 03:09:31 -04:00
# if CONFIG_IDF_TARGET_ESP32
# include "esp_clock_output.h"
# endif
2021-08-18 07:45:51 -04:00
# if SOC_GDMA_SUPPORTED
# include "esp_private/gdma.h"
# endif
2023-08-02 07:21:54 -04:00
# include "esp_private/periph_ctrl.h"
2024-04-02 02:57:00 -04:00
# include "esp_private/esp_gpio_reserve.h"
2021-08-18 07:45:51 -04:00
# include "esp_pm.h"
# include "esp_err.h"
2023-08-02 07:21:54 -04:00
# include "sdkconfig.h"
2021-08-18 07:45:51 -04:00
# ifdef __cplusplus
extern " C " {
# endif
2023-03-20 08:15:12 -04:00
// If ISR handler is allowed to run whilst cache is disabled,
// Make sure all the code and related variables used by the handler are in the SRAM
# if CONFIG_I2S_ISR_IRAM_SAFE
2023-08-02 07:21:54 -04:00
# define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
2023-03-20 08:15:12 -04:00
# define I2S_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
# else
2023-08-02 07:21:54 -04:00
# define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
2023-03-20 08:15:12 -04:00
# define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
# endif //CONFIG_I2S_ISR_IRAM_SAFE
2024-06-03 03:57:49 -04:00
# define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT)
2023-03-20 08:15:12 -04:00
2023-09-07 04:47:26 -04:00
# if SOC_PERIPH_CLK_CTRL_SHARED
2023-09-05 22:55:47 -04:00
# define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
# else
# define I2S_CLOCK_SRC_ATOMIC()
# endif
2023-08-02 07:21:54 -04:00
# if !SOC_RCC_IS_INDEPENDENT
2023-09-05 22:55:47 -04:00
# define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
2023-08-02 07:21:54 -04:00
# else
# define I2S_RCC_ATOMIC()
# endif
2022-04-07 03:32:46 -04:00
# define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL")
2021-08-18 07:45:51 -04:00
/**
* @ brief i2s channel state for checking if the operation in under right driver state
*/
typedef enum {
I2S_CHAN_STATE_REGISTER , /*!< i2s channel is registered (not initialized) */
2022-04-07 03:32:46 -04:00
I2S_CHAN_STATE_READY , /*!< i2s channel is disabled (initialized) */
I2S_CHAN_STATE_RUNNING , /*!< i2s channel is idling (initialized and enabled) */
2021-08-18 07:45:51 -04:00
} i2s_state_t ;
2023-09-07 04:47:26 -04:00
/**
* @ brief Group of I2S callbacks
* @ note The callbacks are all running under ISR environment
* @ note When CONFIG_I2S_ISR_IRAM_SAFE is enabled , the callback itself and functions called by it should be placed in IRAM .
* The variables used in the function should be in the SRAM as well .
* @ note Declare the internal type to remove the dependency of ` i2s_common . h `
*/
typedef struct {
i2s_isr_callback_t on_recv ; /**< Callback of data received event, only for rx channel
* The event data includes DMA buffer address and size that just finished receiving data
*/
i2s_isr_callback_t on_recv_q_ovf ; /**< Callback of receiving queue overflowed event, only for rx channel
* The event data includes buffer size that has been overwritten
*/
i2s_isr_callback_t on_sent ; /**< Callback of data sent event, only for tx channel
* The event data includes DMA buffer address and size that just finished sending data
*/
i2s_isr_callback_t on_send_q_ovf ; /**< Callback of sending queue overflowed event, only for tx channel
* The event data includes buffer size that has been overwritten
*/
} i2s_event_callbacks_internal_t ;
2024-07-03 03:39:23 -04:00
/**
* @ brief LP I2S callbacks
*/
typedef struct {
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
} lp_i2s_evt_cbs_internal_t ;
2021-08-18 07:45:51 -04:00
/**
* @ brief i2s channel level configurations
* @ note It performs as channel handle
*/
typedef struct {
# if SOC_GDMA_SUPPORTED
2022-04-07 03:32:46 -04:00
gdma_channel_handle_t dma_chan ; /*!< gdma channel handle */
# else
intr_handle_t dma_chan ; /*!< interrupt channel handle */
2021-08-18 07:45:51 -04:00
# endif
uint32_t desc_num ; /*!< I2S DMA buffer number, it is also the number of DMA descriptor */
uint32_t frame_num ; /*!< I2S frame number in one DMA buffer. One frame means one-time sample data in all slots */
uint32_t buf_size ; /*!< dma buffer size */
2024-03-26 23:37:51 -04:00
bool auto_clear_after_cb ; /*!< Set to auto clear DMA TX descriptor after callback, i2s will always send zero automatically if no data to send */
bool auto_clear_before_cb ; /*!< Set to auto clear DMA TX descriptor before callback, i2s will always send zero automatically if no data to send */
2021-08-18 07:45:51 -04:00
uint32_t rw_pos ; /*!< reading/writing pointer position */
void * curr_ptr ; /*!< Pointer to current dma buffer */
2023-08-02 07:21:54 -04:00
void * curr_desc ; /*!< Pointer to current dma descriptor used for pre-load */
2021-08-18 07:45:51 -04:00
lldesc_t * * desc ; /*!< dma descriptor array */
uint8_t * * bufs ; /*!< dma buffer array */
} i2s_dma_t ;
/**
* @ brief i2s controller level configurations
* @ note Both i2s rx and tx channel are under its control
*/
typedef struct {
i2s_port_t id ; /*!< i2s port id */
i2s_hal_context_t hal ; /*!< hal context */
uint32_t chan_occupancy ; /*!< channel occupancy (rx/tx) */
bool full_duplex ; /*!< is full_duplex */
i2s_chan_handle_t tx_chan ; /*!< tx channel handler */
i2s_chan_handle_t rx_chan ; /*!< rx channel handler */
int mclk ; /*!< MCK out pin, shared by tx/rx*/
2023-09-11 03:09:31 -04:00
# if CONFIG_IDF_TARGET_ESP32
esp_clock_output_mapping_handle_t mclk_out_hdl ; /*!< The handle of MCLK output signal */
# endif
2021-08-18 07:45:51 -04:00
} i2s_controller_t ;
2022-09-05 07:08:46 -04:00
struct i2s_channel_obj_t {
2021-08-18 07:45:51 -04:00
/* Channel basic information */
2022-04-07 03:32:46 -04:00
i2s_controller_t * controller ; /*!< Parent pointer to controller object */
2021-08-18 07:45:51 -04:00
i2s_comm_mode_t mode ; /*!< i2s channel communication mode */
i2s_role_t role ; /*!< i2s role */
i2s_dir_t dir ; /*!< i2s channel direction */
i2s_dma_t dma ; /*!< i2s dma object */
i2s_state_t state ; /*!< i2s driver state. Ensuring the driver working in a correct sequence */
/* Stored configurations */
2023-09-07 04:47:26 -04:00
int intr_prio_flags ; /*!< i2s interrupt priority flags */
2021-08-18 07:45:51 -04:00
void * mode_info ; /*!< Slot, clock and gpio information of each mode */
2024-08-02 04:21:41 -04:00
bool is_etm_start ; /*!< Whether start by etm tasks */
bool is_etm_stop ; /*!< Whether stop by etm tasks */
2021-08-18 07:45:51 -04:00
# if SOC_I2S_SUPPORTS_APLL
2024-03-25 02:11:33 -04:00
bool apll_en ; /*!< Flag of whether APLL enabled */
2021-08-18 07:45:51 -04:00
# endif
uint32_t active_slot ; /*!< Active slot number */
uint32_t total_slot ; /*!< Total slot number */
/* Locks and queues */
2022-04-07 03:32:46 -04:00
SemaphoreHandle_t mutex ; /*!< Mutex semaphore for the channel operations */
SemaphoreHandle_t binary ; /*!< Binary semaphore for writing / reading / enabling / disabling */
# if CONFIG_PM_ENABLE
2021-08-18 07:45:51 -04:00
esp_pm_lock_handle_t pm_lock ; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */
2022-04-07 03:32:46 -04:00
# endif
2021-08-18 07:45:51 -04:00
QueueHandle_t msg_queue ; /*!< Message queue handler, used for transporting data between interrupt and read/write task */
2024-04-02 02:57:00 -04:00
uint64_t reserve_gpio_mask ; /*!< The gpio mask that has been reserved by I2S */
2023-09-07 04:47:26 -04:00
i2s_event_callbacks_internal_t callbacks ; /*!< Callback functions */
2022-04-07 03:32:46 -04:00
void * user_data ; /*!< User data for callback functions */
2023-11-07 08:06:07 -05:00
void ( * start ) ( i2s_chan_handle_t ) ; /*!< start tx/rx channel */
void ( * stop ) ( i2s_chan_handle_t ) ; /*!< stop tx/rx channel */
2021-08-18 07:45:51 -04:00
} ;
2024-07-03 03:39:23 -04:00
/**
* @ brief lp i2s controller type
*/
typedef struct {
int id ; /*!< lp i2s port id */
lp_i2s_hal_context_t hal ; /*!< hal context */
uint32_t chan_occupancy ; /*!< channel occupancy (rx/tx) */
lp_i2s_chan_handle_t rx_chan ; /*!< rx channel handle */
intr_handle_t intr ; /*!< interrupt handle */
} lp_i2s_controller_t ;
/**
* @ brief lp i2s channel object type
*/
struct lp_i2s_channel_obj_t {
/* Channel basic information */
lp_i2s_controller_t * ctlr ; /*!< Parent pointer to controller object */
i2s_comm_mode_t mode ; /*!< lp i2s channel communication mode */
i2s_role_t role ; /*!< lp i2s role */
i2s_dir_t dir ; /*!< lp i2s channel direction */
i2s_state_t state ; /*!< lp i2s driver state. Ensuring the driver working in a correct sequence */
SemaphoreHandle_t semphr ; /*!< lp i2s event semphr*/
lp_i2s_trans_t trans ; /*!< transaction */
size_t threshold ; /*!< lp i2s threshold*/
lp_i2s_evt_cbs_internal_t cbs ; /*!< callbacks */
void * user_data ; /*!< user data */
} ;
2021-08-18 07:45:51 -04:00
/**
* @ brief i2s platform level configurations
2022-04-07 03:32:46 -04:00
* @ note All i2s controllers ' resources are involved
2021-08-18 07:45:51 -04:00
*/
typedef struct {
2024-07-03 03:39:23 -04:00
portMUX_TYPE spinlock ; /*!< Platform level lock */
i2s_controller_t * controller [ SOC_I2S_NUM ] ; /*!< Controller object */
const char * comp_name [ SOC_I2S_NUM ] ; /*!< The component name that occupied i2s controller */
# if SOC_LP_I2S_SUPPORTED
lp_i2s_controller_t * lp_controller [ SOC_LP_I2S_NUM ] ; /*!< LP controller object*/
const char * lp_comp_name [ SOC_I2S_NUM ] ; /*!< The component name that occupied lp i2s controller */
# endif
2021-08-18 07:45:51 -04:00
} i2s_platform_t ;
2023-09-07 04:47:26 -04:00
extern i2s_platform_t g_i2s ; /*!< Global i2s instance for driver internal use */
2021-08-18 07:45:51 -04:00
2022-04-07 03:32:46 -04:00
/**
* @ brief Initialize I2S DMA interrupt
*
* @ param handle I2S channel handle
* @ param intr_flag I2S interrupt flags , ` ESP_INTR_FLAG_XXX ` defined in ` esp_intr_alloc . h `
* @ return
* - ESP_OK Initialize interrupt success
* - ESP_ERR_INVALID_ARG Wrong port id or NULL pointer
*/
2021-08-18 07:45:51 -04:00
esp_err_t i2s_init_dma_intr ( i2s_chan_handle_t handle , int intr_flag ) ;
2022-04-07 03:32:46 -04:00
/**
* @ brief Free I2S DMA descriptor and DMA buffer
*
* @ param handle I2S channel handle
* @ return
* - ESP_OK Free success
* - ESP_ERR_INVALID_ARG NULL pointer
*/
2021-08-18 07:45:51 -04:00
esp_err_t i2s_free_dma_desc ( i2s_chan_handle_t handle ) ;
2022-04-07 03:32:46 -04:00
/**
* @ brief Allocate memory for I2S DMA descriptor and DMA buffer
*
* @ param handle I2S channel handle
* @ param num Number of DMA descriptors
* @ param bufsize The DMA buffer size
*
* @ return
* - ESP_OK Allocate memory success
* - ESP_ERR_INVALID_ARG NULL pointer or bufsize is too big
2022-12-22 02:16:26 -05:00
* - ESP_ERR_NO_MEM No memory for DMA descriptor and DMA buffer
2022-04-07 03:32:46 -04:00
*/
2021-08-18 07:45:51 -04:00
esp_err_t i2s_alloc_dma_desc ( i2s_chan_handle_t handle , uint32_t num , uint32_t bufsize ) ;
2022-04-07 03:32:46 -04:00
/**
* @ brief Get DMA buffer size
*
* @ param handle I2S channel handle
* @ param data_bit_width Data bit width in one slot
* @ param dma_frame_num Frame number in one DMA buffer
*
* @ return
* - DMA buffer size
*/
2021-08-18 07:45:51 -04:00
uint32_t i2s_get_buf_size ( i2s_chan_handle_t handle , uint32_t data_bit_width , uint32_t dma_frame_num ) ;
2022-04-07 03:32:46 -04:00
/**
2022-09-15 05:27:57 -04:00
* @ brief Get the frequency of the source clock
2022-04-07 03:32:46 -04:00
*
2022-09-15 05:27:57 -04:00
* @ param clk_src clock source
2022-12-22 02:16:26 -05:00
* @ param mclk_freq_hz Expected mclk frequency in Hz
2022-04-07 03:32:46 -04:00
* @ return
2022-09-15 05:27:57 -04:00
* - Actual source clock frequency
2022-04-07 03:32:46 -04:00
*/
2022-09-15 05:27:57 -04:00
uint32_t i2s_get_source_clk_freq ( i2s_clock_src_t clk_src , uint32_t mclk_freq_hz ) ;
2021-08-18 07:45:51 -04:00
2022-04-07 03:32:46 -04:00
/**
* @ brief Check gpio validity and attach to corresponding signal
*
2024-04-02 02:57:00 -04:00
* @ param handle I2S channel handle
2022-04-07 03:32:46 -04:00
* @ param gpio GPIO number
* @ param signal_idx Signal index
* @ param is_input Is input gpio
* @ param is_invert Is invert gpio
*/
2024-04-02 02:57:00 -04:00
void i2s_gpio_check_and_set ( i2s_chan_handle_t handle , int gpio , uint32_t signal_idx , bool is_input , bool is_invert ) ;
2022-04-07 03:32:46 -04:00
/**
* @ brief Check gpio validity and output mclk signal
*
2024-04-02 02:57:00 -04:00
* @ param handle I2S channel handle
2022-04-07 03:32:46 -04:00
* @ param id I2S port id
* @ param gpio_num GPIO number
2023-07-20 05:00:48 -04:00
* @ param clk_src The clock source of this I2S port
2022-04-07 03:32:46 -04:00
* @ param is_invert Is invert the GPIO
* @ return
* - ESP_OK Set mclk output gpio success
* - ESP_ERR_INVALID_ARG Invalid GPIO number
*/
2024-04-02 02:57:00 -04:00
esp_err_t i2s_check_set_mclk ( i2s_chan_handle_t handle , i2s_port_t id , int gpio_num , i2s_clock_src_t clk_src , bool is_invert ) ;
2021-08-18 07:45:51 -04:00
2022-04-07 03:32:46 -04:00
/**
* @ brief Attach data out signal and data in signal to a same gpio
*
2024-04-02 02:57:00 -04:00
* @ param handle I2S channel handle
2022-04-07 03:32:46 -04:00
* @ param gpio GPIO number
* @ param out_sig_idx Data out signal index
* @ param in_sig_idx Data in signal index
*/
2024-04-02 02:57:00 -04:00
void i2s_gpio_loopback_set ( i2s_chan_handle_t handle , int gpio , uint32_t out_sig_idx , uint32_t in_sig_idx ) ;
/**
* @ brief Reserve the GPIO that configured as I2S output signal
*
* @ param handle I2S channel handle
* @ param gpio_num The output gpio number to be reserved
*/
void i2s_output_gpio_reserve ( i2s_chan_handle_t handle , int gpio_num ) ;
/**
* @ brief Revoke the GPIO that configured as I2S output signal
*
* @ param handle I2S channel handle
* @ param gpio_mask The output gpio mask to be revoked
*/
void i2s_output_gpio_revoke ( i2s_chan_handle_t handle , uint64_t gpio_mask ) ;
2021-08-18 07:45:51 -04:00
# ifdef __cplusplus
}
# endif