diff --git a/components/audio_board/CMakeLists.txt b/components/audio_board/CMakeLists.txt index e5d740b77..792440d5f 100644 --- a/components/audio_board/CMakeLists.txt +++ b/components/audio_board/CMakeLists.txt @@ -70,4 +70,13 @@ set(COMPONENT_SRCS ) endif() +if (CONFIG_ESP_AI_THINKER_V2_2_BOARD) +message(STATUS "Current board name is " CONFIG_ESP_AI_THINKER_V2_2_BOARD) +list(APPEND COMPONENT_ADD_INCLUDEDIRS ./ai_thinker_audio_kit_v2_2) +set(COMPONENT_SRCS +./ai_thinker_audio_kit_v2_2/board.c +./ai_thinker_audio_kit_v2_2/board_pins_config.c +) +endif() + register_component() diff --git a/components/audio_board/Kconfig.projbuild b/components/audio_board/Kconfig.projbuild index 67a9e5430..c7aaf1342 100644 --- a/components/audio_board/Kconfig.projbuild +++ b/components/audio_board/Kconfig.projbuild @@ -21,6 +21,8 @@ config ESP32_KORVO_DU1906_BOARD bool "ESP32_KORVO_DU1906" config ESP32_S2_KALUGA_1_V1_2_BOARD bool "ESP32-S2-Kaluga-1 v1.2" +config ESP_AI_THINKER_V2_2_BOARD + bool "ESP32-AiThinker-audio V2.2" endchoice diff --git a/components/audio_board/ai_thinker_audio_kit_v2_2/board.c b/components/audio_board/ai_thinker_audio_kit_v2_2/board.c new file mode 100644 index 000000000..181cee55e --- /dev/null +++ b/components/audio_board/ai_thinker_audio_kit_v2_2/board.c @@ -0,0 +1,162 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "esp_log.h" +#include "board.h" +#include "audio_mem.h" + +#include "periph_sdcard.h" +#include "led_indicator.h" +#include "periph_button.h" + +static const char *TAG = "AUDIO_BOARD"; + +static audio_board_handle_t board_handle = 0; + +audio_board_handle_t audio_board_init(void) +{ + if (board_handle) { + ESP_LOGW(TAG, "The board has already been initialized!"); + return board_handle; + } + board_handle = (audio_board_handle_t) audio_calloc(1, sizeof(struct audio_board_handle)); + AUDIO_MEM_CHECK(TAG, board_handle, return NULL); + board_handle->audio_hal = audio_board_codec_init(); + return board_handle; +} + +audio_hal_handle_t audio_board_codec_init(void) +{ + audio_hal_codec_config_t audio_codec_cfg = AUDIO_CODEC_DEFAULT_CONFIG(); + audio_hal_handle_t codec_hal = audio_hal_init(&audio_codec_cfg, &AUDIO_CODEC_AC101_CODEC_HANDLE); + AUDIO_NULL_CHECK(TAG, codec_hal, return NULL); + return codec_hal; +} + +display_service_handle_t audio_board_led_init(void) +{ + led_indicator_handle_t led = led_indicator_init((gpio_num_t)get_green_led_gpio()); + display_service_config_t display = { + .based_cfg = { + .task_stack = 0, + .task_prio = 0, + .task_core = 0, + .task_func = NULL, + .service_start = NULL, + .service_stop = NULL, + .service_destroy = NULL, + .service_ioctl = led_indicator_pattern, + .service_name = "DISPLAY_serv", + .user_data = NULL, + }, + .instance = led, + }; + + return display_service_create(&display); +} + +display_service_handle_t audio_board_blue_led_init(void) +{ + led_indicator_handle_t led = led_indicator_init((gpio_num_t)get_blue_led_gpio()); + display_service_config_t display = { + .based_cfg = { + .task_stack = 0, + .task_prio = 0, + .task_core = 0, + .task_func = NULL, + .service_start = NULL, + .service_stop = NULL, + .service_destroy = NULL, + .service_ioctl = led_indicator_pattern, + .service_name = "DISPLAY_serv", + .user_data = NULL, + }, + .instance = led, + }; + + return display_service_create(&display); +} + +esp_err_t audio_board_key_init(esp_periph_set_handle_t set) +{ + periph_button_cfg_t btn_cfg = { + .gpio_mask = (1ULL << get_input_rec_id()) + | (1ULL << get_input_mode_id()) + | (1ULL << get_input_play_id()) + | (1ULL << get_input_set_id()) + | (1ULL << get_input_volup_id()) + | (1ULL << get_input_voldown_id()), + }; + esp_periph_handle_t button_handle = periph_button_init(&btn_cfg); + AUDIO_NULL_CHECK(TAG, button_handle, return ESP_ERR_ADF_MEMORY_LACK); + esp_err_t ret = ESP_OK; + ret = esp_periph_start(set, button_handle); + + return ret; +} + +esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set, periph_sdcard_mode_t mode) +{ + if (mode != SD_MODE_1_LINE) { + ESP_LOGE(TAG, "current board only support 1-line SD mode!"); + return ESP_FAIL; + } + + periph_sdcard_cfg_t sdcard_cfg = { + .root = "/sdcard", + .card_detect_pin = get_sdcard_intr_gpio(), // GPIO_NUM_34 + .mode = mode + }; + esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg); + esp_err_t ret = esp_periph_start(set, sdcard_handle); + int retry_time = 5; + bool mount_flag = false; + while (retry_time --) { + if (periph_sdcard_is_mounted(sdcard_handle)) { + mount_flag = true; + break; + } else { + vTaskDelay(500 / portTICK_PERIOD_MS); + } + } + if (mount_flag == false) { + ESP_LOGE(TAG, "Sdcard mount failed"); + return ESP_FAIL; + } + return ret; +} + +audio_board_handle_t audio_board_get_handle(void) +{ + return board_handle; +} + +esp_err_t audio_board_deinit(audio_board_handle_t audio_board) +{ + esp_err_t ret = ESP_OK; + ret = audio_hal_deinit(audio_board->audio_hal); + audio_free(audio_board); + board_handle = NULL; + return ret; +} diff --git a/components/audio_board/ai_thinker_audio_kit_v2_2/board.h b/components/audio_board/ai_thinker_audio_kit_v2_2/board.h new file mode 100644 index 000000000..eb18df8c4 --- /dev/null +++ b/components/audio_board/ai_thinker_audio_kit_v2_2/board.h @@ -0,0 +1,119 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _AUDIO_BOARD_H_ +#define _AUDIO_BOARD_H_ + +#include "audio_hal.h" +#include "board_def.h" +#include "board_pins_config.h" +#include "esp_peripherals.h" +#include "display_service.h" +#include "periph_sdcard.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Audio board handle + */ +struct audio_board_handle { + audio_hal_handle_t audio_hal; /*!< audio hardware abstract layer handle */ +}; + +typedef struct audio_board_handle *audio_board_handle_t; + +/** + * @brief Initialize audio board + * + * @return The audio board handle + */ +audio_board_handle_t audio_board_init(void); + +/** + * @brief Initialize codec chip + * + * @return The audio hal handle + */ +audio_hal_handle_t audio_board_codec_init(void); + +/** + * @brief Initialize led peripheral and display service + * + * @return The audio display service handle + */ +display_service_handle_t audio_board_led_init(void); + +/** + * @brief Initialize led peripheral and display service + * + * @return The audio display service handle + */ +display_service_handle_t audio_board_blue_led_init(void); + +/** + * @brief Initialize key peripheral + * + * @param set The handle of esp_periph_set_handle_t + * + * @return + * - ESP_OK, success + * - Others, fail + */ +esp_err_t audio_board_key_init(esp_periph_set_handle_t set); + +/** + * @brief Initialize sdcard peripheral + * + * @param set The handle of esp_periph_set_handle_t + * + * @return + * - ESP_OK, success + * - Others, fail + */ +esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set, periph_sdcard_mode_t mode); + +/** + * @brief Query audio_board_handle + * + * @return The audio board handle + */ +audio_board_handle_t audio_board_get_handle(void); + +/** + * @brief Uninitialize the audio board + * + * @param audio_board The handle of audio board + * + * @return 0 success, + * others fail + */ +esp_err_t audio_board_deinit(audio_board_handle_t audio_board); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/audio_board/ai_thinker_audio_kit_v2_2/board_def.h b/components/audio_board/ai_thinker_audio_kit_v2_2/board_def.h new file mode 100644 index 000000000..32ee6b431 --- /dev/null +++ b/components/audio_board/ai_thinker_audio_kit_v2_2/board_def.h @@ -0,0 +1,94 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _AUDIO_BOARD_DEFINITION_H_ +#define _AUDIO_BOARD_DEFINITION_H_ + +#define SDCARD_OPEN_FILE_NUM_MAX 5 +#define SDCARD_INTR_GPIO GPIO_NUM_34 + +#define BUTTON_REC_ID GPIO_NUM_36 // key 1 +#define BUTTON_MODE_ID GPIO_NUM_13 // key 2 +#define BUTTON_PLAY_ID GPIO_NUM_19 // key 3 +#define BUTTON_SET_ID GPIO_NUM_23 // key 4 +#define BUTTON_VOLDOWN_ID GPIO_NUM_18 // key 5 +#define BUTTON_VOLUP_ID GPIO_NUM_5 // key 6 + + +#define HEADPHONE_DETECT GPIO_NUM_5 +#define PA_ENABLE_GPIO GPIO_NUM_21 + +#define BLUE_LED_GPIO GPIO_NUM_19 +#define GREEN_LED_GPIO GPIO_NUM_22 + +extern audio_hal_func_t AUDIO_CODEC_AC101_CODEC_HANDLE; + +#define AUDIO_CODEC_DEFAULT_CONFIG(){ \ + .adc_input = AUDIO_HAL_ADC_INPUT_LINE1, \ + .dac_output = AUDIO_HAL_DAC_OUTPUT_ALL, \ + .codec_mode = AUDIO_HAL_CODEC_MODE_BOTH, \ + .i2s_iface = { \ + .mode = AUDIO_HAL_MODE_SLAVE, \ + .fmt = AUDIO_HAL_I2S_NORMAL, \ + .samples = AUDIO_HAL_48K_SAMPLES, \ + .bits = AUDIO_HAL_BIT_LENGTH_16BITS, \ + }, \ +}; + +#define INPUT_KEY_NUM 6 + +#define INPUT_KEY_DEFAULT_INFO() { \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_REC, \ + .act_id = BUTTON_REC_ID, \ + }, \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_MODE, \ + .act_id = BUTTON_MODE_ID, \ + }, \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_SET, \ + .act_id = BUTTON_SET_ID, \ + }, \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_PLAY, \ + .act_id = BUTTON_PLAY_ID, \ + }, \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_VOLUP, \ + .act_id = BUTTON_VOLUP_ID, \ + }, \ + { \ + .type = PERIPH_ID_BUTTON, \ + .user_id = INPUT_KEY_USER_ID_VOLDOWN, \ + .act_id = BUTTON_VOLDOWN_ID, \ + } \ +} + +#endif diff --git a/components/audio_board/ai_thinker_audio_kit_v2_2/board_pins_config.c b/components/audio_board/ai_thinker_audio_kit_v2_2/board_pins_config.c new file mode 100644 index 000000000..4f64f5041 --- /dev/null +++ b/components/audio_board/ai_thinker_audio_kit_v2_2/board_pins_config.c @@ -0,0 +1,176 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2019 + * + * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "esp_log.h" +#include "driver/gpio.h" +#include +#include "board.h" +#include "audio_error.h" +#include "audio_mem.h" + +static const char *TAG = "A1S"; + +esp_err_t get_i2c_pins(i2c_port_t port, i2c_config_t *i2c_config) +{ + AUDIO_NULL_CHECK(TAG, i2c_config, return ESP_FAIL); + if (port == I2C_NUM_0 || port == I2C_NUM_1) { + i2c_config->sda_io_num = GPIO_NUM_33; + i2c_config->scl_io_num = GPIO_NUM_32; + } else { + i2c_config->sda_io_num = -1; + i2c_config->scl_io_num = -1; + ESP_LOGE(TAG, "i2c port %d is not supported", port); + return ESP_FAIL; + } + return ESP_OK; +} + +esp_err_t get_i2s_pins(i2s_port_t port, i2s_pin_config_t *i2s_config) +{ + AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL); + if (port == I2S_NUM_0) { + i2s_config->bck_io_num = GPIO_NUM_27; + i2s_config->ws_io_num = GPIO_NUM_26; + i2s_config->data_out_num = GPIO_NUM_25; + i2s_config->data_in_num = GPIO_NUM_35; + } else { + memset(i2s_config, -1, sizeof(i2s_pin_config_t)); + ESP_LOGE(TAG, "i2s port %d is not supported", port); + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t get_spi_pins(spi_bus_config_t *spi_config, spi_device_interface_config_t *spi_device_interface_config) +{ + AUDIO_NULL_CHECK(TAG, spi_config, return ESP_FAIL); + AUDIO_NULL_CHECK(TAG, spi_device_interface_config, return ESP_FAIL); + + spi_config->mosi_io_num = GPIO_NUM_23; + spi_config->miso_io_num = -1; + spi_config->sclk_io_num = GPIO_NUM_18; + spi_config->quadwp_io_num = -1; + spi_config->quadhd_io_num = -1; + + spi_device_interface_config->spics_io_num = -1; + + ESP_LOGW(TAG, "SPI interface is not supported"); + return ESP_OK; +} + +esp_err_t i2s_mclk_gpio_select(i2s_port_t i2s_num, gpio_num_t gpio_num) +{ + if (i2s_num >= I2S_NUM_MAX) { + ESP_LOGE(TAG, "Does not support i2s number(%d)", i2s_num); + return ESP_ERR_INVALID_ARG; + } + if (gpio_num != GPIO_NUM_0 && gpio_num != GPIO_NUM_1 && gpio_num != GPIO_NUM_3) { + ESP_LOGE(TAG, "Only support GPIO0/GPIO1/GPIO3, gpio_num:%d", gpio_num); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGI(TAG, "I2S%d, MCLK output by GPIO%d", i2s_num, gpio_num); + if (i2s_num == I2S_NUM_0) { + if (gpio_num == GPIO_NUM_0) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + WRITE_PERI_REG(PIN_CTRL, 0xFFF0); + } else if (gpio_num == GPIO_NUM_1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); + WRITE_PERI_REG(PIN_CTRL, 0xF0F0); + } else { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); + WRITE_PERI_REG(PIN_CTRL, 0xFF00); + } + } + return ESP_OK; +} + +// sdcard + +int8_t get_sdcard_intr_gpio(void) +{ + return SDCARD_INTR_GPIO; +} + +int8_t get_sdcard_open_file_num_max(void) +{ + return SDCARD_OPEN_FILE_NUM_MAX; +} + +// input-output pins + +int8_t get_headphone_detect_gpio(void) +{ + return HEADPHONE_DETECT; +} + +int8_t get_pa_enable_gpio(void) +{ + return PA_ENABLE_GPIO; +} + +// adc button id + +int8_t get_input_rec_id(void) +{ + return BUTTON_REC_ID; +} + +int8_t get_input_mode_id(void) +{ + return BUTTON_MODE_ID; +} + +int8_t get_input_set_id(void) +{ + return BUTTON_SET_ID; +} + +int8_t get_input_play_id(void) +{ + return BUTTON_PLAY_ID; +} + +int8_t get_input_volup_id(void) +{ + return BUTTON_VOLUP_ID; +} + +int8_t get_input_voldown_id(void) +{ + return BUTTON_VOLDOWN_ID; +} + +// led pins + +int8_t get_green_led_gpio(void) +{ + return GREEN_LED_GPIO; +} + +int8_t get_blue_led_gpio(void) +{ + return BLUE_LED_GPIO; +} + diff --git a/components/audio_board/component.mk b/components/audio_board/component.mk index 35766bcaf..bdc30e94e 100644 --- a/components/audio_board/component.mk +++ b/components/audio_board/component.mk @@ -41,3 +41,9 @@ ifdef CONFIG_ESP32_S2_KALUGA_1_V1_2_BOARD COMPONENT_ADD_INCLUDEDIRS += ./esp32_s2_kaluga_1_v1_2 COMPONENT_SRCDIRS += ./esp32_s2_kaluga_1_v1_2 endif + +ifdef CONFIG_ESP_AI_THINKER_V2_2_BOARD +COMPONENT_ADD_INCLUDEDIRS += ./ai_thinker_audio_kit_v2_2 +COMPONENT_SRCDIRS += ./ai_thinker_audio_kit_v2_2 +endif + diff --git a/components/audio_hal/CMakeLists.txt b/components/audio_hal/CMakeLists.txt index a1c6633d8..2eed4b849 100644 --- a/components/audio_hal/CMakeLists.txt +++ b/components/audio_hal/CMakeLists.txt @@ -4,6 +4,7 @@ set(COMPONENT_ADD_INCLUDEDIRS ./include ./driver/es8311 ./driver/es7243 ./driver/es7148 + ./driver/ac101 ./driver/tas5805m ./driver/zl38063 ./driver/zl38063/api_lib @@ -21,6 +22,7 @@ set(COMPONENT_SRCS ./audio_hal.c ./driver/es8374/es8374.c ./driver/es8311/es8311.c ./driver/es7243/es7243.c + ./driver/ac101/ac101.c ./driver/es7148/es7148.c ./driver/tas5805m/tas5805m.c ./driver/zl38063/zl38063.c diff --git a/components/audio_hal/component.mk b/components/audio_hal/component.mk index 983f5f557..e8329fbfa 100644 --- a/components/audio_hal/component.mk +++ b/components/audio_hal/component.mk @@ -19,3 +19,6 @@ COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/driver/zl38063/firmware -lfirmware COMPONENT_ADD_INCLUDEDIRS += ./driver/tas5805m ./driver/es7148 COMPONENT_SRCDIRS += ./driver/tas5805m ./driver/es7148 + +COMPONENT_ADD_INCLUDEDIRS += ./driver/ac101 +COMPONENT_SRCDIRS += ./driver/ac101 \ No newline at end of file diff --git a/components/audio_hal/driver/ac101/ac101.c b/components/audio_hal/driver/ac101/ac101.c new file mode 100644 index 000000000..6ddde9d6a --- /dev/null +++ b/components/audio_hal/driver/ac101/ac101.c @@ -0,0 +1,493 @@ +// code from https://github.com/donny681/esp-adf/blob/master/components/audio_hal/driver/AC101/AC101.c + +#include +#include "driver/i2c.h" +#include "board.h" +#include "esp_log.h" +#include "ac101.h" + +static char *TAG = "AC101"; +static int vol = 70; + +static i2c_config_t ac_i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 100000}; + +/* + * operate function of codec + */ +audio_hal_func_t AUDIO_CODEC_AC101_CODEC_HANDLE = { + .audio_codec_initialize = ac101_init, + .audio_codec_deinitialize = ac101_deinit, + .audio_codec_ctrl = ac101_ctrl_state, + .audio_codec_config_iface = ac101_config_i2s, + .audio_codec_set_mute = ac101_set_voice_mute, + .audio_codec_set_volume = ac101_set_voice_volume, + .audio_codec_get_volume = ac101_get_voice_volume, +}; + +#define AC_ASSERT(a, format, b, ...) \ + if ((a) != 0) \ + { \ + ESP_LOGE(TAG, format, ##__VA_ARGS__); \ + return b; \ + } + +static esp_err_t ac101_write_reg(uint8_t reg_addr, uint16_t val) +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + esp_err_t ret = 0; + uint8_t send_buff[4]; + send_buff[0] = (AC101_ADDR << 1); + send_buff[1] = reg_addr; + send_buff[2] = (val >> 8) & 0xff; + send_buff[3] = val & 0xff; + ret |= i2c_master_start(cmd); + ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN); + ret |= i2c_master_stop(cmd); + ret |= i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +static esp_err_t i2c_example_master_read_slave(uint8_t DevAddr, uint8_t reg, uint8_t *data_rd, size_t size) +{ + if (size == 0) + { + return ESP_OK; + } + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (DevAddr << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (DevAddr << 1) | READ_BIT, ACK_CHECK_EN); //check or not + i2c_master_read(cmd, data_rd, size, ACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +static uint16_t ac101_read_reg(uint8_t reg_addr) +{ + uint16_t val = 0; + uint8_t data_rd[2]; + i2c_example_master_read_slave(AC101_ADDR, reg_addr, data_rd, 2); + val = (data_rd[0] << 8) + data_rd[1]; + return val; +} + +static int i2c_init() +{ + int res = 0; + get_i2c_pins(I2C_NUM_0, &ac_i2c_cfg); + res |= i2c_param_config(I2C_NUM_0, &ac_i2c_cfg); + res |= i2c_driver_install(I2C_NUM_0, ac_i2c_cfg.mode, 0, 0, 0); + AC_ASSERT(res, "i2c_init error", -1); + return res; +} + +void set_codec_clk(audio_hal_iface_samples_t sampledata) +{ + uint16_t sample_fre; + switch (sampledata) + { + case AUDIO_HAL_08K_SAMPLES: + sample_fre = 8000; + break; + case AUDIO_HAL_11K_SAMPLES: + sample_fre = 11025; + break; + case AUDIO_HAL_16K_SAMPLES: + sample_fre = 16000; + break; + case AUDIO_HAL_22K_SAMPLES: + sample_fre = 22050; + break; + case AUDIO_HAL_24K_SAMPLES: + sample_fre = 24000; + break; + case AUDIO_HAL_32K_SAMPLES: + sample_fre = 32000; + break; + case AUDIO_HAL_44K_SAMPLES: + sample_fre = 44100; + break; + case AUDIO_HAL_48K_SAMPLES: + sample_fre = 48000; + break; + default: + sample_fre = 44100; + } + ac101_write_reg(I2S_SR_CTRL, sample_fre); +} + +esp_err_t ac101_init(audio_hal_codec_config_t *codec_cfg) +{ + + // if(i2c_init() < 0) return -1; + + // esp_err_t res; + + esp_err_t res = ESP_OK; + + i2c_init(); // ESP32 in master mode + + res = ac101_write_reg(CHIP_AUDIO_RS, 0x123); + vTaskDelay(1000 / portTICK_PERIOD_MS); + + if (res != ESP_OK) + { + ESP_LOGE(TAG, "reset failed!"); + return res; + } + else + { + ESP_LOGW(TAG, "reset succeed"); + } + res |= ac101_write_reg(SPKOUT_CTRL, 0xe880); + + //Enable the PLL from 256*44.1KHz MCLK source + res |= ac101_write_reg(PLL_CTRL1, 0x014f); + //res |= ac101_write_reg(PLL_CTRL2, 0x83c0); + res |= ac101_write_reg(PLL_CTRL2, 0x8600); + + //Clocking system + res |= ac101_write_reg(SYSCLK_CTRL, 0x8b08); + res |= ac101_write_reg(MOD_CLK_ENA, 0x800c); + res |= ac101_write_reg(MOD_RST_CTRL, 0x800c); + res |= ac101_write_reg(I2S_SR_CTRL, 0x7000); //sample rate + //AIF config + res |= ac101_write_reg(I2S1LCK_CTRL, 0x8850); //BCLK/LRCK + res |= ac101_write_reg(I2S1_SDOUT_CTRL, 0xc000); // + res |= ac101_write_reg(I2S1_SDIN_CTRL, 0xc000); + res |= ac101_write_reg(I2S1_MXR_SRC, 0x2200); // + + res |= ac101_write_reg(ADC_SRCBST_CTRL, 0xccc4); + res |= ac101_write_reg(ADC_SRC, 0x2020); + res |= ac101_write_reg(ADC_DIG_CTRL, 0x8000); + res |= ac101_write_reg(ADC_APC_CTRL, 0xbbc3); + + //Path Configuration + res |= ac101_write_reg(DAC_MXR_SRC, 0xcc00); + res |= ac101_write_reg(DAC_DIG_CTRL, 0x8000); + res |= ac101_write_reg(OMIXER_SR, 0x0081); + res |= ac101_write_reg(OMIXER_DACA_CTRL, 0xf080); //} + + //* Enable Speaker output + res |= ac101_write_reg(0x58, 0xeabd); + + ESP_LOGI(TAG, "init done"); + ac101_pa_power(true); + return res; +} + +int ac101_get_spk_volume(void) +{ + int res; + res = ac101_read_reg(SPKOUT_CTRL); + res &= 0x1f; + return res * 2; +} + +esp_err_t ac101_set_spk_volume(uint8_t volume) +{ + if (volume > 0x3f) + volume = 0x3f; + volume = volume / 2; + + uint16_t res; + esp_err_t ret; + + res = ac101_read_reg(SPKOUT_CTRL); + res &= (~0x1f); + volume &= 0x1f; + res |= volume; + ret = ac101_write_reg(SPKOUT_CTRL, res); + return ret; +} + +int ac101_get_earph_volume(void) +{ + int res; + res = ac101_read_reg(HPOUT_CTRL); + return (res >> 4) & 0x3f; +} + +esp_err_t ac101_set_earph_volume(uint8_t volume) +{ + if (volume > 0x3f) + volume = 0x3f; + + uint16_t res, tmp; + esp_err_t ret; + res = ac101_read_reg(HPOUT_CTRL); + tmp = ~(0x3f << 4); + res &= tmp; + volume &= 0x3f; + res |= (volume << 4); + ret = ac101_write_reg(HPOUT_CTRL, res); + return ret; +} + +esp_err_t ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain, ac_output_mixer_source_t source) +{ + uint16_t regval, temp, clrbit; + esp_err_t ret; + regval = ac101_read_reg(OMIXER_BST1_CTRL); + switch (source) + { + case SRC_MIC1: + temp = (gain & 0x7) << 6; + clrbit = ~(0x7 << 6); + break; + case SRC_MIC2: + temp = (gain & 0x7) << 3; + clrbit = ~(0x7 << 3); + break; + case SRC_LINEIN: + temp = (gain & 0x7); + clrbit = ~0x7; + break; + default: + return -1; + } + regval &= clrbit; + regval |= temp; + ret = ac101_write_reg(OMIXER_BST1_CTRL, regval); + return ret; +} + +esp_err_t AC101_start(ac_module_t mode) +{ + + esp_err_t res = 0; + if (mode == AC_MODULE_LINE) + { + res |= ac101_write_reg(0x51, 0x0408); + res |= ac101_write_reg(0x40, 0x8000); + res |= ac101_write_reg(0x50, 0x3bc0); + } + if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) + { + //I2S1_SDOUT_CTRL + //res |= ac101_write_reg(PLL_CTRL2, 0x8120); + res |= ac101_write_reg(0x04, 0x800c); + res |= ac101_write_reg(0x05, 0x800c); + //res |= ac101_write_reg(0x06, 0x3000); + } + if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) + { + //* Enable Headphoe output + res |= ac101_write_reg(OMIXER_DACA_CTRL, 0xff80); + res |= ac101_write_reg(HPOUT_CTRL, 0xc3c1); + res |= ac101_write_reg(HPOUT_CTRL, 0xcb00); + vTaskDelay(100 / portTICK_PERIOD_MS); + res |= ac101_write_reg(HPOUT_CTRL, 0xfbc0); + + //* Enable Speaker output + res |= ac101_write_reg(SPKOUT_CTRL, 0xeabd); + vTaskDelay(10 / portTICK_PERIOD_MS); + ac101_set_voice_volume((int)(vol * 63 / 100 + 0.5)); + } + + return res; +} + +esp_err_t AC101_stop(ac_module_t mode) +{ + esp_err_t res = 0; + res |= ac101_write_reg(HPOUT_CTRL, 0x01); //disable earphone + res |= ac101_write_reg(SPKOUT_CTRL, 0xe880); //disable speaker + return res; +} + +esp_err_t ac101_deinit(void) +{ + + return ac101_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset +} + +esp_err_t ac101_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state) +{ + int res = 0; + int es_mode_t = 0; + + switch (mode) + { + case AUDIO_HAL_CODEC_MODE_ENCODE: + es_mode_t = AC_MODULE_ADC; + break; + case AUDIO_HAL_CODEC_MODE_LINE_IN: + es_mode_t = AC_MODULE_LINE; + break; + case AUDIO_HAL_CODEC_MODE_DECODE: + es_mode_t = AC_MODULE_DAC; + break; + case AUDIO_HAL_CODEC_MODE_BOTH: + es_mode_t = AC_MODULE_ADC_DAC; + break; + default: + es_mode_t = AC_MODULE_DAC; + ESP_LOGW(TAG, "Codec mode not support, default is decode mode"); + break; + } + if (AUDIO_HAL_CTRL_STOP == ctrl_state) + { + res = AC101_stop(es_mode_t); + } + else + { + res = AC101_start(es_mode_t); + } + return res; +} + +esp_err_t ac101_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface) +{ + esp_err_t res = 0; + int bits = 0; + int fmat = 0; + int sample_fre = 0; + uint16_t regval; + switch (iface->bits) //0x10 + { + // case AUDIO_HAL_BIT_LENGTH_8BITS: + // bits = BIT_LENGTH_8_BITS; + // break; + case AUDIO_HAL_BIT_LENGTH_16BITS: + bits = BIT_LENGTH_16_BITS; + break; + case AUDIO_HAL_BIT_LENGTH_24BITS: + bits = BIT_LENGTH_24_BITS; + break; + default: + bits = BIT_LENGTH_16_BITS; + } + + switch (iface->fmt) //0x10 + { + case AUDIO_HAL_I2S_NORMAL: + fmat = 0x0; + break; + case AUDIO_HAL_I2S_LEFT: + fmat = 0x01; + break; + case AUDIO_HAL_I2S_RIGHT: + fmat = 0x02; + break; + case AUDIO_HAL_I2S_DSP: + fmat = 0x03; + break; + default: + fmat = 0x00; + break; + } + + switch (iface->samples) + { + case AUDIO_HAL_08K_SAMPLES: + sample_fre = 8000; + break; + case AUDIO_HAL_11K_SAMPLES: + sample_fre = 11025; + break; + case AUDIO_HAL_16K_SAMPLES: + sample_fre = 16000; + break; + case AUDIO_HAL_22K_SAMPLES: + sample_fre = 22050; + break; + case AUDIO_HAL_24K_SAMPLES: + sample_fre = 24000; + break; + case AUDIO_HAL_32K_SAMPLES: + sample_fre = 32000; + break; + case AUDIO_HAL_44K_SAMPLES: + sample_fre = 44100; + break; + case AUDIO_HAL_48K_SAMPLES: + sample_fre = 48000; + break; + default: + sample_fre = 44100; + } + regval = ac101_read_reg(I2S1LCK_CTRL); + regval &= 0xffc3; + regval |= (iface->mode << 15); + regval |= (bits << 4); + regval |= (fmat << 2); + res |= ac101_write_reg(I2S1LCK_CTRL, regval); + res |= ac101_write_reg(I2S_SR_CTRL, sample_fre); + return res; +} + +esp_err_t AC101_i2s_config_clock(ac_i2s_clock_t *cfg) +{ + esp_err_t res = 0; + uint16_t regval = 0; + regval = ac101_read_reg(I2S1LCK_CTRL); + regval &= 0xe03f; + regval |= (cfg->bclk_div << 9); + regval |= (cfg->lclk_div << 6); + res = ac101_write_reg(I2S1LCK_CTRL, regval); + return res; +} + +esp_err_t ac101_set_voice_mute(bool enable) +{ + esp_err_t res = 0; + + if (enable) + { + res = ac101_set_earph_volume(0); + res |= ac101_set_spk_volume(0); + } + else + { + int vol_tmp = (int)(vol * 63 / 100 + 0.5); + res = ac101_set_earph_volume(vol_tmp); + res |= ac101_set_spk_volume(vol_tmp); + } + return res; +} + +esp_err_t ac101_set_voice_volume(int volume) +{ + esp_err_t res; + int vol_tmp = (int)(volume * 63 / 100 + 0.5); + res = ac101_set_earph_volume(vol_tmp); + res |= ac101_set_spk_volume(vol_tmp); + vol = volume; + return res; +} + +esp_err_t ac101_get_voice_volume(int *volume) +{ + *volume = vol; + return 0; +} + +void ac101_pa_power(bool enable) +{ + gpio_config_t io_conf; + memset(&io_conf, 0, sizeof(io_conf)); + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = BIT(PA_ENABLE_GPIO); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 0; + gpio_config(&io_conf); + if (enable) + { + gpio_set_level(PA_ENABLE_GPIO, 1); + } + else + { + gpio_set_level(PA_ENABLE_GPIO, 0); + } +} diff --git a/components/audio_hal/driver/ac101/ac101.h b/components/audio_hal/driver/ac101/ac101.h new file mode 100644 index 000000000..188bf7b02 --- /dev/null +++ b/components/audio_hal/driver/ac101/ac101.h @@ -0,0 +1,170 @@ +// code from https://github.com/donny681/esp-adf/blob/master/components/audio_hal/driver/AC101/AC101.h + +#ifndef __AC101_H__ +#define __AC101_H__ + +//#include "sdkconfig.h" +#include "esp_types.h" +#include "audio_hal.h" + +#define AC101_ADDR 0x1a /*!< Device address*/ + +#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ +#define READ_BIT I2C_MASTER_READ /*!< I2C master read */ +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NACK_VAL 0x1 /*!< I2C nack value */ + +#define CHIP_AUDIO_RS 0x00 +#define PLL_CTRL1 0x01 +#define PLL_CTRL2 0x02 +#define SYSCLK_CTRL 0x03 +#define MOD_CLK_ENA 0x04 +#define MOD_RST_CTRL 0x05 +#define I2S_SR_CTRL 0x06 +#define I2S1LCK_CTRL 0x10 +#define I2S1_SDOUT_CTRL 0x11 +#define I2S1_SDIN_CTRL 0x12 +#define I2S1_MXR_SRC 0x13 +#define I2S1_VOL_CTRL1 0x14 +#define I2S1_VOL_CTRL2 0x15 +#define I2S1_VOL_CTRL3 0x16 +#define I2S1_VOL_CTRL4 0x17 +#define I2S1_MXR_GAIN 0x18 +#define ADC_DIG_CTRL 0x40 +#define ADC_VOL_CTRL 0x41 +#define HMIC_CTRL1 0x44 +#define HMIC_CTRL2 0x45 +#define HMIC_STATUS 0x46 +#define DAC_DIG_CTRL 0x48 +#define DAC_VOL_CTRL 0x49 +#define DAC_MXR_SRC 0x4c +#define DAC_MXR_GAIN 0x4d +#define ADC_APC_CTRL 0x50 +#define ADC_SRC 0x51 +#define ADC_SRCBST_CTRL 0x52 +#define OMIXER_DACA_CTRL 0x53 +#define OMIXER_SR 0x54 +#define OMIXER_BST1_CTRL 0x55 +#define HPOUT_CTRL 0x56 +#define SPKOUT_CTRL 0x58 +#define AC_DAC_DAPCTRL 0xa0 +#define AC_DAC_DAPHHPFC 0xa1 +#define AC_DAC_DAPLHPFC 0xa2 +#define AC_DAC_DAPLHAVC 0xa3 +#define AC_DAC_DAPLLAVC 0xa4 +#define AC_DAC_DAPRHAVC 0xa5 +#define AC_DAC_DAPRLAVC 0xa6 +#define AC_DAC_DAPHGDEC 0xa7 +#define AC_DAC_DAPLGDEC 0xa8 +#define AC_DAC_DAPHGATC 0xa9 +#define AC_DAC_DAPLGATC 0xaa +#define AC_DAC_DAPHETHD 0xab +#define AC_DAC_DAPLETHD 0xac +#define AC_DAC_DAPHGKPA 0xad +#define AC_DAC_DAPLGKPA 0xae +#define AC_DAC_DAPHGOPA 0xaf +#define AC_DAC_DAPLGOPA 0xb0 +#define AC_DAC_DAPOPT 0xb1 +#define DAC_DAP_ENA 0xb5 + +typedef enum{ + SAMPLE_RATE_8000 = 0x0000, + SAMPLE_RATE_11052 = 0x1000, + SAMPLE_RATE_12000 = 0x2000, + SAMPLE_RATE_16000 = 0x3000, + SAMPLE_RATE_22050 = 0x4000, + SAMPLE_RATE_24000 = 0x5000, + SAMPLE_RATE_32000 = 0x6000, + SAMPLE_RATE_44100 = 0x7000, + SAMPLE_RATE_48000 = 0x8000, + SAMPLE_RATE_96000 = 0x9000, + SAMPLE_RATE_192000 = 0xa000, +}ac_adda_fs_i2s1_t; + +typedef enum{ + BCLK_DIV_1 = 0x0, + BCLK_DIV_2 = 0x1, + BCLK_DIV_4 = 0x2, + BCLK_DIV_6 = 0x3, + BCLK_DIV_8 = 0x4, + BCLK_DIV_12 = 0x5, + BCLK_DIV_16 = 0x6, + BCLK_DIV_24 = 0x7, + BCLK_DIV_32 = 0x8, + BCLK_DIV_48 = 0x9, + BCLK_DIV_64 = 0xa, + BCLK_DIV_96 = 0xb, + BCLK_DIV_128 = 0xc, + BCLK_DIV_192 = 0xd, + +}ac_i2s1_bclk_div_t; + +typedef enum{ + LRCK_DIV_16 =0x0, + LRCK_DIV_32 =0x1, + LRCK_DIV_64 =0x2, + LRCK_DIV_128 =0x3, + LRCK_DIV_256 =0x4, +}ac_i2s1_lrck_div_t; + +typedef enum { + BIT_LENGTH_8_BITS = 0x00, + BIT_LENGTH_16_BITS = 0x01, + BIT_LENGTH_20_BITS = 0x02, + BIT_LENGTH_24_BITS = 0x03, +} ac_bits_length_t; + +typedef enum { + AC_MODE_MIN = -1, + AC_MODE_SLAVE = 0x00, + AC_MODE_MASTER = 0x01, + AC_MODE_MAX, +} ac_mode_sm_t; + +typedef enum { + AC_MODULE_MIN = -1, + AC_MODULE_ADC = 0x01, + AC_MODULE_DAC = 0x02, + AC_MODULE_ADC_DAC = 0x03, + AC_MODULE_LINE = 0x04, + AC_MODULE_MAX +} ac_module_t; + +typedef enum{ + SRC_MIC1 = 1, + SRC_MIC2 = 2, + SRC_LINEIN = 3, +}ac_output_mixer_source_t; + +typedef enum { + GAIN_N45DB = 0, + GAIN_N30DB = 1, + GAIN_N15DB = 2, + GAIN_0DB = 3, + GAIN_15DB = 4, + GAIN_30DB = 5, + GAIN_45DB = 6, + GAIN_60DB = 7, +} ac_output_mixer_gain_t; + +/** + * @brief Configure AC101 clock + */ +typedef struct { + ac_i2s1_bclk_div_t bclk_div; /*!< bits clock divide */ + ac_i2s1_lrck_div_t lclk_div; /*!< WS clock divide */ +} ac_i2s_clock_t; + + +esp_err_t ac101_init(audio_hal_codec_config_t* codec_cfg); +esp_err_t ac101_deinit(void); +esp_err_t ac101_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state); +esp_err_t ac101_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t* iface); +esp_err_t ac101_set_voice_mute(bool enable); +esp_err_t ac101_set_voice_volume(int volume); +esp_err_t ac101_get_voice_volume(int* volume); +void ac101_pa_power(bool enable); + +#endif