[固件生成] 【Hardware Configuration (JSON)】 { "chip": "ESP32", "peripherals": [ { "type": "audio_a

More
3 weeks 17 hours ago #44 by btt
New Topic
硬件配置(JSON格式):
Code:
【Hardware Configuration (JSON)】 { "chip": "ESP32", "peripherals": [ { "type": "audio_amp", "model": "TDA7492P", "pins": { "bclk": "GPIO17", "lrc": "GPIO18", "din": "GPIO16" } }, { "type": "microphone", "model": "MAX98357A", "pins": { "bclk": "GPIO34", "ws": "GPIO35", "data": "GPIO39" } }, { "type": "button", "model": null, "pins": { "signal_name": "GPIO0" } }, { "type": "led", "model": null, "pins": { "signal_name": "GPIO2" } } ] }

原理图:


生成的固件代码:
Code:
```c #include <stdio.h> #include <string.h> #include "esp_err.h" #include "esp_log.h" #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_bt_api.h" #include "esp_a2dp_api.h" #include "esp_avrc_api.h" #include "driver/gpio.h" #include "driver/i2s.h" static const char *TAG = "A2DP_SINK"; // Pin definitions #define I2S_BCLK_GPIO 17 #define I2S_LRC_GPIO 18 #define I2S_DIN_GPIO 16 #define MIC_BCLK_GPIO 34 // not used in this example #define MIC_WS_GPIO 35 #define MIC_DATA_GPIO 39 #define BUTTON_GPIO 0 #define LED_GPIO 2 // I2S configuration #define I2S_PORT I2S_NUM_0 #define I2S_SAMPLE_RATE 44100 #define I2S_BITS_PER_SAMPLE I2S_BITS_PER_SAMPLE_16BIT #define I2S_CHANNEL_FORMAT I2S_CHANNEL_FMT_RIGHT_LEFT #define I2S_COMM_FORMAT I2S_COMM_FORMAT_STAND_I2S // A2DP state static bool a2dp_connected = false; static bool a2dp_playing = false; static uint8_t volume = 100; // Function prototypes static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param); static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); static void bt_app_avrc_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param); static void i2s_init(void); static void i2s_write_data(const uint8_t *data, size_t len); static void button_handler(void *arg); static void led_update(void); void app_main(void) { // Init I2S i2s_init(); // Init GPIOs gpio_config_t io_conf = {}; // Button: input with pull-up io_conf.intr_type = GPIO_INTR_POSEDGE; io_conf.pin_bit_mask = (1ULL << BUTTON_GPIO); io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 1; gpio_config(&io_conf); // LED: output io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.pin_bit_mask = (1ULL << LED_GPIO); io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pull_up_en = 0; io_conf.pull_down_en = 0; gpio_config(&io_conf); gpio_set_level(LED_GPIO, 0); // Install button ISR service and handler gpio_install_isr_service(0); gpio_isr_handler_add(BUTTON_GPIO, button_handler, NULL); // Initialize Bluetooth ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_err_t ret = esp_bt_controller_init(&bt_cfg); if (ret != ESP_OK) { ESP_LOGE(TAG, "initialize controller failed: %s", esp_err_to_name(ret)); return; } ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT); if (ret != ESP_OK) { ESP_LOGE(TAG, "enable controller failed: %s", esp_err_to_name(ret)); return; } ret = esp_bluedroid_init(); if (ret != ESP_OK) { ESP_LOGE(TAG, "initialize bluedroid failed: %s", esp_err_to_name(ret)); return; } ret = esp_bluedroid_enable(); if (ret != ESP_OK) { ESP_LOGE(TAG, "enable bluedroid failed: %s", esp_err_to_name(ret)); return; } // Set device name esp_bt_dev_set_device_name("ESP32_A2DP_Sink"); esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); // Register callbacks esp_bt_gap_register_callback(bt_app_gap_cb); esp_a2d_register_callback(bt_app_a2d_cb); esp_a2d_sink_init(); esp_avrc_ct_init(); esp_avrc_ct_register_callback(bt_app_avrc_cb); // Start bluetooth ESP_LOGI(TAG, "A2DP Sink initialized. Waiting for connection..."); led_update(); // Main loop does nothing, everything handled by callbacks while (1) { vTaskDelay(pdMS_TO_TICKS(1000)); } } static void i2s_init(void) { i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_TX, .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE, .channel_format = I2S_CHANNEL_FORMAT, .communication_format = I2S_COMM_FORMAT, .intr_alloc_flags = 0, .dma_buf_count = 8, .dma_buf_len = 64, }; i2s_pin_config_t pin_config = { .bck_io_num = I2S_BCLK_GPIO, .ws_io_num = I2S_LRC_GPIO, .data_out_num = I2S_DIN_GPIO, .data_in_num = I2S_PIN_NO_CHANGE, }; ESP_ERROR_CHECK(i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL)); ESP_ERROR_CHECK(i2s_set_pin(I2S_PORT, &pin_config)); i2s_zero_dma_buffer(I2S_PORT); } static void i2s_write_data(const uint8_t *data, size_t len) { size_t bytes_written; esp_err_t ret = i2s_write(I2S_PORT, data, len, &bytes_written, portMAX_DELAY); if (ret != ESP_OK) { ESP_LOGE(TAG, "I2S write error: %s", esp_err_to_name(ret)); } } static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) { switch (event) { case ESP_BT_GAP_AUTH_CMPL_EVT: if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) { ESP_LOGI(TAG, "Authentication succeeded: %s", param->auth_cmpl.device_name); } else { ESP_LOGE(TAG, "Authentication failed"); } break; default: break; } } static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { switch (event) { case ESP_A2D_CONNECTION_STATE_EVT: { esp_a2d_connection_state_t state = param->conn_stat.state; if (state == ESP_A2D_CONNECTION_STATE_CONNECTED) { ESP_LOGI(TAG, "A2DP connected"); a2dp_connected = true; } else if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) { ESP_LOGI(TAG, "A2DP disconnected"); a2dp_connected = false; a2dp_playing = false; } led_update(); break; } case ESP_A2D_AUDIO_STATE_EVT: { esp_a2d_audio_state_t audio_state = param->audio_stat.state; if (audio_state == ESP_A2D_AUDIO_STATE_STARTED) { ESP_LOGI(TAG, "Audio started"); a2dp_playing = true; } else if (audio_state == ESP_A2D_AUDIO_STATE_STOPPED) { ESP_LOGI(TAG, "Audio stopped"); a2dp_playing = false; } break; } case ESP_A2D_PROF_STATE_EVT: { // Not used break; } default: break; } } static void bt_app_avrc_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) { switch (event) { case ESP_AVRC_CT_CONNECTION_STATE_EVT: break; case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: break; case ESP_AVRC_CT_META_RSP_EVT: if (param->meta_rsp.attr_id == ESP_AVRC_MD_ATTR_PLAYBACK_STATE) { // Handle playback state } break; case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: if (param->change_ntfy.event_id == ESP_AVRC_CT_EVENT_PLAYBACK_STATUS_CHANGED) { // Playback status changed } break; default: break; } } // A2DP data callback is registered via esp_a2d_sink_register_data_callback() // We need to provide data handler before enabling A2DP sink // Usually called from within esp_a2d_sink_init() after setting callback. // Let's define it as a simple function and register. static void a2dp_data_callback(const uint8_t *data, uint32_t len) { if (len > 0) { i2s_write_data(data, len); } } // We need to register data callback after init, but before any connection. // So we do it in app_main after a2d sink init. // Actually esp_a2d_sink_register_data_callback() must be called before esp_a2d_sink_init() // Change order: register callback before init. // Let's adjust: in app_main, after esp_a2d_register_callback, call esp_a2d_sink_register_data_callback(a2dp_data_callback), then esp_a2d_sink_init(). // Update app_main accordingly. // Also, we need to declare a2dp_data_callback before its use. // Reordering: in app_main after esp_a2d_register_callback, add: // esp_a2d_sink_register_data_callback(a2dp_data_callback); // then esp_a2d_sink_init(); // This comment is for implementation; I will rewrite app_main with correct order. // Button handler: simple toggle play/pause via AVRCP static void button_handler(void *arg) { static TickType_t last_press = 0; TickType_t now = xTaskGetTickCountFromISR(); if ((now - last_press) > pdMS_TO_TICKS(200)) { last_press = now; // Send play/pause passthrough command esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_PRESSED); // Release after short delay (handled by system, but we can send release immediately) esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_RELEASED); } } static void led_update(void) { if (a2dp_connected) { gpio_set_level(LED_GPIO, 1); // solid on when connected } else { // Blink slowly static bool led_state = false; led_state = !led_state; gpio_set_level(LED_GPIO, led_state ? 0 : 1); // toggle each call (call every second) } } ```

点击这里使用固件生成器

Please Log in or Create an account to join the conversation.

Time to create page: 0.220 seconds