/* * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "driver/gpio.h" #include "driver/ledc.h" #include "driver/spi_master.h" #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" #include "bsp/esp-bsp.h" #include "bsp/display.h" #include "bsp/touch.h" #include "esp_lcd_st77916.h" #include "esp_lcd_touch_cst816s.h" #include "esp_lvgl_port.h" #include "bsp_err_check.h" #include #include #include #include #include #include "driver/uart.h" #include "esp_sleep.h" #include "esp_timer.h" #include "sdkconfig.h" #define GPIO_WAKEUP_LEVEL 0 static const char *TAG = "BSP"; static lv_disp_t *disp; static lv_indev_t *disp_indev = NULL; static esp_lcd_touch_handle_t tp; // LCD touch handle static esp_lcd_panel_handle_t panel_handle = NULL; static i2c_master_bus_handle_t i2c_handle = NULL; static sdmmc_card_t *bsp_sdcard = NULL; // Global uSD card handler static bool i2c_initialized = false; esp_err_t bsp_i2c_init(void) { /* I2C was initialized before */ if (i2c_initialized) { return ESP_OK; } const i2c_master_bus_config_t i2c_config = { .i2c_port = BSP_I2C_NUM, .sda_io_num = BSP_I2C_SDA, .scl_io_num = BSP_I2C_SCL, .clk_source = I2C_CLK_SRC_DEFAULT, }; BSP_ERROR_CHECK_RETURN_ERR(i2c_new_master_bus(&i2c_config, &i2c_handle)); i2c_initialized = true; return ESP_OK; } esp_err_t bsp_i2c_deinit(void) { BSP_ERROR_CHECK_RETURN_ERR(i2c_del_master_bus(i2c_handle)); i2c_initialized = false; return ESP_OK; } i2c_master_bus_handle_t bsp_i2c_get_handle(void) { bsp_i2c_init(); return i2c_handle; } void bsp_i2c_set_handle(i2c_master_bus_handle_t handle) { i2c_handle = handle; i2c_initialized = true; } // Bit number used to represent command and parameter #define LCD_CMD_BITS 32 #define LCD_PARAM_BITS 8 #define LCD_LEDC_CH CONFIG_BSP_DISPLAY_BRIGHTNESS_LEDC_CH esp_err_t bsp_display_brightness_init(void) { // Setup LEDC peripheral for PWM backlight control const ledc_channel_config_t LCD_backlight_channel = { .gpio_num = BSP_LCD_BACKLIGHT, .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LCD_LEDC_CH, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LEDC_TIMER_0, .duty = 0, .hpoint = 0 }; const ledc_timer_config_t LCD_backlight_timer = { .speed_mode = LEDC_LOW_SPEED_MODE, .duty_resolution = LEDC_TIMER_10_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 4000, .clk_cfg = LEDC_AUTO_CLK }; BSP_ERROR_CHECK_RETURN_ERR(ledc_timer_config(&LCD_backlight_timer)); BSP_ERROR_CHECK_RETURN_ERR(ledc_channel_config(&LCD_backlight_channel)); return ESP_OK; } esp_err_t bsp_display_brightness_set(int brightness_percent) { if (brightness_percent > 100) { brightness_percent = 100; } if (brightness_percent < 0) { brightness_percent = 0; } ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent); uint32_t duty_cycle = (1023 * brightness_percent) / 100; // LEDC resolution set to 10bits, thus: 100% = 1023 BSP_ERROR_CHECK_RETURN_ERR(ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle)); BSP_ERROR_CHECK_RETURN_ERR(ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH)); return ESP_OK; } esp_err_t bsp_display_backlight_off(void) { return bsp_display_brightness_set(0); } esp_err_t bsp_display_backlight_on(void) { return bsp_display_brightness_set(100); } static const st77916_lcd_init_cmd_t vendor_specific_init_default[] = { {0xF0, (uint8_t []){0x28}, 1, 0}, {0xF2, (uint8_t []){0x28}, 1, 0}, {0x73, (uint8_t []){0xF0}, 1, 0}, {0x7C, (uint8_t []){0xD1}, 1, 0}, {0x83, (uint8_t []){0xE0}, 1, 0}, {0x84, (uint8_t []){0x61}, 1, 0}, {0xF2, (uint8_t []){0x82}, 1, 0}, {0xF0, (uint8_t []){0x00}, 1, 0}, {0xF0, (uint8_t []){0x01}, 1, 0}, {0xF1, (uint8_t []){0x01}, 1, 0}, {0xB0, (uint8_t []){0x56}, 1, 0}, {0xB1, (uint8_t []){0x4D}, 1, 0}, {0xB2, (uint8_t []){0x24}, 1, 0}, {0xB4, (uint8_t []){0x87}, 1, 0}, {0xB5, (uint8_t []){0x44}, 1, 0}, {0xB6, (uint8_t []){0x8B}, 1, 0}, {0xB7, (uint8_t []){0x40}, 1, 0}, {0xB8, (uint8_t []){0x86}, 1, 0}, {0xBA, (uint8_t []){0x00}, 1, 0}, {0xBB, (uint8_t []){0x08}, 1, 0}, {0xBC, (uint8_t []){0x08}, 1, 0}, {0xBD, (uint8_t []){0x00}, 1, 0}, {0xC0, (uint8_t []){0x80}, 1, 0}, {0xC1, (uint8_t []){0x10}, 1, 0}, {0xC2, (uint8_t []){0x37}, 1, 0}, {0xC3, (uint8_t []){0x80}, 1, 0}, {0xC4, (uint8_t []){0x10}, 1, 0}, {0xC5, (uint8_t []){0x37}, 1, 0}, {0xC6, (uint8_t []){0xA9}, 1, 0}, {0xC7, (uint8_t []){0x41}, 1, 0}, {0xC8, (uint8_t []){0x01}, 1, 0}, {0xC9, (uint8_t []){0xA9}, 1, 0}, {0xCA, (uint8_t []){0x41}, 1, 0}, {0xCB, (uint8_t []){0x01}, 1, 0}, {0xD0, (uint8_t []){0x91}, 1, 0}, {0xD1, (uint8_t []){0x68}, 1, 0}, {0xD2, (uint8_t []){0x68}, 1, 0}, {0xF5, (uint8_t []){0x00, 0xA5}, 2, 0}, {0xDD, (uint8_t []){0x4F}, 1, 0}, {0xDE, (uint8_t []){0x4F}, 1, 0}, {0xF1, (uint8_t []){0x10}, 1, 0}, {0xF0, (uint8_t []){0x00}, 1, 0}, {0xF0, (uint8_t []){0x02}, 1, 0}, {0xE0, (uint8_t []){0xF0, 0x0A, 0x10, 0x09, 0x09, 0x36, 0x35, 0x33, 0x4A, 0x29, 0x15, 0x15, 0x2E, 0x34}, 14, 0}, {0xE1, (uint8_t []){0xF0, 0x0A, 0x0F, 0x08, 0x08, 0x05, 0x34, 0x33, 0x4A, 0x39, 0x15, 0x15, 0x2D, 0x33}, 14, 0}, {0xF0, (uint8_t []){0x10}, 1, 0}, {0xF3, (uint8_t []){0x10}, 1, 0}, {0xE0, (uint8_t []){0x07}, 1, 0}, {0xE1, (uint8_t []){0x00}, 1, 0}, {0xE2, (uint8_t []){0x00}, 1, 0}, {0xE3, (uint8_t []){0x00}, 1, 0}, {0xE4, (uint8_t []){0xE0}, 1, 0}, {0xE5, (uint8_t []){0x06}, 1, 0}, {0xE6, (uint8_t []){0x21}, 1, 0}, {0xE7, (uint8_t []){0x01}, 1, 0}, {0xE8, (uint8_t []){0x05}, 1, 0}, {0xE9, (uint8_t []){0x02}, 1, 0}, {0xEA, (uint8_t []){0xDA}, 1, 0}, {0xEB, (uint8_t []){0x00}, 1, 0}, {0xEC, (uint8_t []){0x00}, 1, 0}, {0xED, (uint8_t []){0x0F}, 1, 0}, {0xEE, (uint8_t []){0x00}, 1, 0}, {0xEF, (uint8_t []){0x00}, 1, 0}, {0xF8, (uint8_t []){0x00}, 1, 0}, {0xF9, (uint8_t []){0x00}, 1, 0}, {0xFA, (uint8_t []){0x00}, 1, 0}, {0xFB, (uint8_t []){0x00}, 1, 0}, {0xFC, (uint8_t []){0x00}, 1, 0}, {0xFD, (uint8_t []){0x00}, 1, 0}, {0xFE, (uint8_t []){0x00}, 1, 0}, {0xFF, (uint8_t []){0x00}, 1, 0}, {0x60, (uint8_t []){0x40}, 1, 0}, {0x61, (uint8_t []){0x04}, 1, 0}, {0x62, (uint8_t []){0x00}, 1, 0}, {0x63, (uint8_t []){0x42}, 1, 0}, {0x64, (uint8_t []){0xD9}, 1, 0}, {0x65, (uint8_t []){0x00}, 1, 0}, {0x66, (uint8_t []){0x00}, 1, 0}, {0x67, (uint8_t []){0x00}, 1, 0}, {0x68, (uint8_t []){0x00}, 1, 0}, {0x69, (uint8_t []){0x00}, 1, 0}, {0x6A, (uint8_t []){0x00}, 1, 0}, {0x6B, (uint8_t []){0x00}, 1, 0}, {0x70, (uint8_t []){0x40}, 1, 0}, {0x71, (uint8_t []){0x03}, 1, 0}, {0x72, (uint8_t []){0x00}, 1, 0}, {0x73, (uint8_t []){0x42}, 1, 0}, {0x74, (uint8_t []){0xD8}, 1, 0}, {0x75, (uint8_t []){0x00}, 1, 0}, {0x76, (uint8_t []){0x00}, 1, 0}, {0x77, (uint8_t []){0x00}, 1, 0}, {0x78, (uint8_t []){0x00}, 1, 0}, {0x79, (uint8_t []){0x00}, 1, 0}, {0x7A, (uint8_t []){0x00}, 1, 0}, {0x7B, (uint8_t []){0x00}, 1, 0}, {0x80, (uint8_t []){0x48}, 1, 0}, {0x81, (uint8_t []){0x00}, 1, 0}, {0x82, (uint8_t []){0x06}, 1, 0}, {0x83, (uint8_t []){0x02}, 1, 0}, {0x84, (uint8_t []){0xD6}, 1, 0}, {0x85, (uint8_t []){0x04}, 1, 0}, {0x86, (uint8_t []){0x00}, 1, 0}, {0x87, (uint8_t []){0x00}, 1, 0}, {0x88, (uint8_t []){0x48}, 1, 0}, {0x89, (uint8_t []){0x00}, 1, 0}, {0x8A, (uint8_t []){0x08}, 1, 0}, {0x8B, (uint8_t []){0x02}, 1, 0}, {0x8C, (uint8_t []){0xD8}, 1, 0}, {0x8D, (uint8_t []){0x04}, 1, 0}, {0x8E, (uint8_t []){0x00}, 1, 0}, {0x8F, (uint8_t []){0x00}, 1, 0}, {0x90, (uint8_t []){0x48}, 1, 0}, {0x91, (uint8_t []){0x00}, 1, 0}, {0x92, (uint8_t []){0x0A}, 1, 0}, {0x93, (uint8_t []){0x02}, 1, 0}, {0x94, (uint8_t []){0xDA}, 1, 0}, {0x95, (uint8_t []){0x04}, 1, 0}, {0x96, (uint8_t []){0x00}, 1, 0}, {0x97, (uint8_t []){0x00}, 1, 0}, {0x98, (uint8_t []){0x48}, 1, 0}, {0x99, (uint8_t []){0x00}, 1, 0}, {0x9A, (uint8_t []){0x0C}, 1, 0}, {0x9B, (uint8_t []){0x02}, 1, 0}, {0x9C, (uint8_t []){0xDC}, 1, 0}, {0x9D, (uint8_t []){0x04}, 1, 0}, {0x9E, (uint8_t []){0x00}, 1, 0}, {0x9F, (uint8_t []){0x00}, 1, 0}, {0xA0, (uint8_t []){0x48}, 1, 0}, {0xA1, (uint8_t []){0x00}, 1, 0}, {0xA2, (uint8_t []){0x05}, 1, 0}, {0xA3, (uint8_t []){0x02}, 1, 0}, {0xA4, (uint8_t []){0xD5}, 1, 0}, {0xA5, (uint8_t []){0x04}, 1, 0}, {0xA6, (uint8_t []){0x00}, 1, 0}, {0xA7, (uint8_t []){0x00}, 1, 0}, {0xA8, (uint8_t []){0x48}, 1, 0}, {0xA9, (uint8_t []){0x00}, 1, 0}, {0xAA, (uint8_t []){0x07}, 1, 0}, {0xAB, (uint8_t []){0x02}, 1, 0}, {0xAC, (uint8_t []){0xD7}, 1, 0}, {0xAD, (uint8_t []){0x04}, 1, 0}, {0xAE, (uint8_t []){0x00}, 1, 0}, {0xAF, (uint8_t []){0x00}, 1, 0}, {0xB0, (uint8_t []){0x48}, 1, 0}, {0xB1, (uint8_t []){0x00}, 1, 0}, {0xB2, (uint8_t []){0x09}, 1, 0}, {0xB3, (uint8_t []){0x02}, 1, 0}, {0xB4, (uint8_t []){0xD9}, 1, 0}, {0xB5, (uint8_t []){0x04}, 1, 0}, {0xB6, (uint8_t []){0x00}, 1, 0}, {0xB7, (uint8_t []){0x00}, 1, 0}, {0xB8, (uint8_t []){0x48}, 1, 0}, {0xB9, (uint8_t []){0x00}, 1, 0}, {0xBA, (uint8_t []){0x0B}, 1, 0}, {0xBB, (uint8_t []){0x02}, 1, 0}, {0xBC, (uint8_t []){0xDB}, 1, 0}, {0xBD, (uint8_t []){0x04}, 1, 0}, {0xBE, (uint8_t []){0x00}, 1, 0}, {0xBF, (uint8_t []){0x00}, 1, 0}, {0xC0, (uint8_t []){0x10}, 1, 0}, {0xC1, (uint8_t []){0x47}, 1, 0}, {0xC2, (uint8_t []){0x56}, 1, 0}, {0xC3, (uint8_t []){0x65}, 1, 0}, {0xC4, (uint8_t []){0x74}, 1, 0}, {0xC5, (uint8_t []){0x88}, 1, 0}, {0xC6, (uint8_t []){0x99}, 1, 0}, {0xC7, (uint8_t []){0x01}, 1, 0}, {0xC8, (uint8_t []){0xBB}, 1, 0}, {0xC9, (uint8_t []){0xAA}, 1, 0}, {0xD0, (uint8_t []){0x10}, 1, 0}, {0xD1, (uint8_t []){0x47}, 1, 0}, {0xD2, (uint8_t []){0x56}, 1, 0}, {0xD3, (uint8_t []){0x65}, 1, 0}, {0xD4, (uint8_t []){0x74}, 1, 0}, {0xD5, (uint8_t []){0x88}, 1, 0}, {0xD6, (uint8_t []){0x99}, 1, 0}, {0xD7, (uint8_t []){0x01}, 1, 0}, {0xD8, (uint8_t []){0xBB}, 1, 0}, {0xD9, (uint8_t []){0xAA}, 1, 0}, {0xF3, (uint8_t []){0x01}, 1, 0}, {0xF0, (uint8_t []){0x00}, 1, 0}, {0x21, (uint8_t []){}, 0, 0}, {0x11, (uint8_t []){}, 0, 0}, {0x00, (uint8_t []){}, 0, 120}, }; esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io) { esp_err_t ret = ESP_OK; assert(config != NULL && config->max_transfer_sz > 0); ESP_RETURN_ON_ERROR(bsp_display_brightness_init(), TAG, "Brightness init failed"); /* Initialize I2C */ BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init()); ESP_LOGD(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = { .sclk_io_num = BSP_LCD_PCLK, .data0_io_num = BSP_LCD_DATA0, .data1_io_num = BSP_LCD_DATA1, .data2_io_num = BSP_LCD_DATA2, .data3_io_num = BSP_LCD_DATA3, .max_transfer_sz = config->max_transfer_sz, }; ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed"); ESP_LOGD(TAG, "Install panel IO"); const esp_lcd_panel_io_spi_config_t io_config = { .dc_gpio_num = BSP_LCD_DC, .cs_gpio_num = BSP_LCD_CS, .pclk_hz = BSP_LCD_PIXEL_CLOCK_HZ, .lcd_cmd_bits = LCD_CMD_BITS, .lcd_param_bits = LCD_PARAM_BITS, .spi_mode = 0, .trans_queue_depth = 1, .flags = { .quad_mode = true, }, }; ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, ret_io), err, TAG, "New panel IO failed"); ESP_LOGD(TAG, "Install LCD driver"); const st77916_vendor_config_t vendor_config = { .init_cmds = vendor_specific_init_default, .init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(vendor_specific_init_default[0]), .flags = { .use_qspi_interface = 1, }, }; esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = BSP_LCD_RST, // Shared with Touch reset .color_space = BSP_LCD_COLOR_SPACE, .bits_per_pixel = BSP_LCD_BITS_PER_PIXEL, .flags = { .reset_active_high = true, }, .vendor_config = (void *) &vendor_config, }; ESP_LOGI(TAG, "Install st77916 panel driver"); ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(*ret_io, (const esp_lcd_panel_dev_config_t *)&panel_config, ret_panel)); esp_lcd_panel_reset(*ret_panel); esp_lcd_panel_init(*ret_panel); esp_lcd_panel_disp_on_off(*ret_panel, true); return ret; err: if (*ret_panel) { esp_lcd_panel_del(*ret_panel); } if (*ret_io) { esp_lcd_panel_io_del(*ret_io); } spi_bus_free(BSP_LCD_SPI_NUM); return ret; } static lv_disp_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg) { assert(cfg != NULL); esp_lcd_panel_io_handle_t io_handle = NULL; const bsp_display_config_t bsp_disp_cfg = { .max_transfer_sz = (BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT) * sizeof(uint16_t), }; BSP_ERROR_CHECK_RETURN_NULL(bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle)); esp_lcd_panel_disp_on_off(panel_handle, true); /* Add LCD screen */ ESP_LOGD(TAG, "Add LCD screen"); const lvgl_port_display_cfg_t disp_cfg = { .io_handle = io_handle, .panel_handle = panel_handle, .buffer_size = cfg->buffer_size, .double_buffer = cfg->double_buffer, .hres = BSP_LCD_H_RES, .vres = BSP_LCD_V_RES, .monochrome = false, /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ .rotation = { .swap_xy = false, .mirror_x = false, .mirror_y = false, }, .flags = { .buff_dma = cfg->flags.buff_dma, .buff_spiram = cfg->flags.buff_spiram, .swap_bytes = true, // .default_dummy_draw = cfg->flags.default_dummy_draw, } }; return lvgl_port_add_disp(&disp_cfg); } esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t *ret_touch) { /* Initialize I2C */ BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init()); /* Initialize touch */ esp_lcd_touch_config_t tp_cfg = { .x_max = BSP_LCD_H_RES, .y_max = BSP_LCD_V_RES, .rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset .int_gpio_num = BSP_LCD_TOUCH_INT, .levels = { .reset = 0, .interrupt = 0, }, .flags = { .swap_xy = 0, .mirror_x = 0, .mirror_y = 0, }, }; esp_lcd_panel_io_handle_t tp_io_handle = NULL; esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG(); ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c_v2(i2c_handle, &tp_io_config, &tp_io_handle), TAG, ""); ESP_RETURN_ON_ERROR(esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, ret_touch), TAG, "New CST816S failed"); return ESP_OK; } static lv_indev_t *bsp_display_indev_init(lv_disp_t *disp) { BSP_ERROR_CHECK_RETURN_NULL(bsp_touch_new(NULL, &tp)); assert(tp); /* Add touch input (for selected screen) */ const lvgl_port_touch_cfg_t touch_cfg = { .disp = disp, .handle = tp, }; return lvgl_port_add_touch(&touch_cfg); } lv_disp_t *bsp_display_start(void) { bsp_display_cfg_t cfg = { .lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(), .buffer_size = BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT, #if CONFIG_BSP_LCD_DRAW_BUF_DOUBLE .double_buffer = 1, #else .double_buffer = 0, #endif .flags = { .buff_dma = true, .buff_spiram = false, } }; return bsp_display_start_with_config(&cfg); } lv_disp_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg) { assert(cfg != NULL); (lvgl_port_init(&cfg->lvgl_port_cfg)); BSP_ERROR_CHECK_RETURN_NULL(bsp_display_brightness_init()); BSP_NULL_CHECK(disp = bsp_display_lcd_init(cfg), NULL); lv_display_set_user_data(disp, (void *)panel_handle); BSP_NULL_CHECK(disp_indev = bsp_display_indev_init(disp), NULL); return disp; } lv_indev_t *bsp_display_get_input_dev(void) { return disp_indev; } bool bsp_display_lock(uint32_t timeout_ms) { return lvgl_port_lock(timeout_ms); } void bsp_display_unlock(void) { lvgl_port_unlock(); } esp_err_t bsp_power_init(bool power_en) { gpio_config_t power_gpio_config = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = BIT64(BSP_POWER_OFF), }; #if defined(BSP_POWER_CODEC_EN) power_gpio_config.pin_bit_mask |= BIT64(BSP_POWER_CODEC_EN); #endif ESP_ERROR_CHECK(gpio_config(&power_gpio_config)); gpio_set_level(BSP_POWER_OFF, !power_en); #if defined(BSP_POWER_CODEC_EN) gpio_set_level(BSP_POWER_CODEC_EN, power_en); ESP_LOGI(TAG, "Using PCB version V1.2"); #else ESP_LOGI(TAG, "Using PCB version V1.0"); #endif vTaskDelay(pdMS_TO_TICKS(100)); return ESP_OK; } sdmmc_card_t *bsp_sdcard_get_handle(void) { return bsp_sdcard; } void bsp_sdcard_get_sdmmc_host(const int slot, sdmmc_host_t *config) { assert(config); sdmmc_host_t host_config = SDMMC_HOST_DEFAULT(); memcpy(config, &host_config, sizeof(sdmmc_host_t)); } void bsp_sdcard_sdmmc_get_slot(const int slot, sdmmc_slot_config_t *config) { assert(config); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); /* SD card is connected to Slot 0 pins. Slot 0 uses IO MUX, so not specifying the pins here */ slot_config.cmd = BSP_SD_CMD; slot_config.clk = BSP_SD_CLK; slot_config.d0 = BSP_SD_D0; slot_config.width = 1; slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; *config = slot_config; } esp_err_t bsp_sdcard_sdmmc_mount(bsp_sdcard_cfg_t *cfg) { sdmmc_host_t sdhost = {0}; sdmmc_slot_config_t sdslot = {0}; const esp_vfs_fat_sdmmc_mount_config_t mount_config = { #ifdef CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL .format_if_mount_failed = true, #else .format_if_mount_failed = false, #endif .max_files = 5, .allocation_unit_size = 16 * 1024 }; assert(cfg); if (!cfg->mount) { cfg->mount = &mount_config; } if (!cfg->host) { bsp_sdcard_get_sdmmc_host(SDMMC_HOST_SLOT_0, &sdhost); cfg->host = &sdhost; } if (!cfg->slot.sdmmc) { bsp_sdcard_sdmmc_get_slot(SDMMC_HOST_SLOT_0, &sdslot); cfg->slot.sdmmc = &sdslot; } #if CONFIG_FATFS_LFN_NONE ESP_LOGW(TAG, "Warning: Long filenames on SD card are disabled in menuconfig!"); #endif return esp_vfs_fat_sdmmc_mount(BSP_SD_MOUNT_POINT, cfg->host, cfg->slot.sdmmc, cfg->mount, &bsp_sdcard); } esp_err_t bsp_sdcard_mount(void) { bsp_sdcard_cfg_t cfg = {0}; return bsp_sdcard_sdmmc_mount(&cfg); } esp_err_t bsp_sdcard_unmount(void) { esp_err_t ret = ESP_OK; ret |= esp_vfs_fat_sdcard_unmount(BSP_SD_MOUNT_POINT, bsp_sdcard); bsp_sdcard = NULL; return ret; } esp_err_t bsp_set_head_led(bool on) { return gpio_set_level(BSP_HEAD_LED, !on); } esp_err_t bsp_set_peripheral_power(bool on) { return gpio_set_level(BSP_POWER_OFF, !on); }