Open liruya opened 10 months ago
@liruya which esp32_camera version are you using? Can you share your initialization code for the LCD and the Camera?
I test the esp-idf/5.1.2 + esp32_camera v2.0.6 and didn't see this error.
@liruya which esp32_camera version are you using? Can you share your initialization code for the LCD and the Camera?
I test the esp-idf/5.1.2 + esp32_camera v2.0.6 and didn't see this error.
esp32-camera版本2.0.6, 单独使用Camera没有问题, 问题出在Camera和LCD i80接口/RGB接口同时使用时. Camera和LCD同时使用, 后初始化的会失败. 目前定位问题出在中断配置, 推测是因为LCD和Camera用的同一个中断源, 但是分别配置中断, 导致后初始化的会分配中断失败.
@liruya which esp32_camera version are you using? Can you share your initialization code for the LCD and the Camera?
I test the esp-idf/5.1.2 + esp32_camera v2.0.6 and didn't see this error.
void lcd_disp_init(void) {
#if LCD_PIN_BL >= 0
ESP_LOGI(TAG, "Turn off LCD backlight");
gpio_config_t bl_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(LCD_PIN_BL)
};
ESP_ERROR_CHECK(gpio_config(&bl_gpio_config));
gpio_set_level(LCD_PIN_BL, LCD_BL_LEVEL_OFF);
#endif
ESP_LOGI(TAG, "Initialize Intel 8080 bus");
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.clk_src = LCD_CLK_SRC_PLL240M,
.dc_gpio_num = LCD_PIN_DC,
.wr_gpio_num = LCD_PIN_WR,
.data_gpio_nums = {
LCD_PIN_DATA0,
LCD_PIN_DATA1,
LCD_PIN_DATA2,
LCD_PIN_DATA3,
LCD_PIN_DATA4,
LCD_PIN_DATA5,
LCD_PIN_DATA6,
LCD_PIN_DATA7,
LCD_PIN_DATA8,
LCD_PIN_DATA9,
LCD_PIN_DATA10,
LCD_PIN_DATA11,
LCD_PIN_DATA12,
LCD_PIN_DATA13,
LCD_PIN_DATA14,
LCD_PIN_DATA15
},
.bus_width = LCD_I80BUS_WIDTH,
.max_transfer_bytes = LCD_WIDTH * 100 * sizeof(uint16_t),
.psram_trans_align = 64,
.sram_trans_align = 4
};
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = LCD_PIN_CS,
.pclk_hz = LCD_PCLK_HZ,
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1
},
.flags = {
.swap_color_bytes = 0, // !LV_COLOR_16_SWAP
},
.on_color_trans_done = lvgl_flush_ready,
.user_ctx = &lv_disp_drv,
.lcd_cmd_bits = LCD_CMD_BITS,
.lcd_param_bits = LCD_PARAM_BITS
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
ESP_LOGI(TAG, "Install LCD driver of st7789");
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = LCD_PIN_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16
};
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &lcd_panel_handle));
esp_lcd_panel_reset(lcd_panel_handle);
esp_lcd_panel_init(lcd_panel_handle);
#if LCD_SWAP_XY
esp_lcd_panel_swap_xy(lcd_panel_handle, true);
#endif
#if LCD_MIRROR_X || LCD_MIRROR_Y
esp_lcd_panel_mirror(lcd_panel_handle, LCD_MIRROR_X, LCD_MIRROR_Y);
#endif
esp_lcd_panel_set_gap(lcd_panel_handle, 0, 0);
// user can flush pre-defined pattern to the screen before we turn on the screen or backlight
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(lcd_panel_handle, true));
}
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RST,
.pin_xclk = CAM_PIN_XCLK,
.pin_sccb_sda = CAM_PIN_SDA,
.pin_sccb_scl = CAM_PIN_SCL,
.pin_pclk = CAM_PIN_PCLK,
.pin_href = CAM_PIN_HSYNC,
.pin_vsync = CAM_PIN_VSYNC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.xclk_freq_hz = 2000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_RGB565,
.frame_size = FRAMESIZE_QVGA,
.jpeg_quality = 12, // 0-63, for OV series camera sensors, lower number means higher quality
.fb_count = 1, //When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode.
.fb_location = CAMERA_FB_IN_PSRAM,
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
.sccb_i2c_port = 0
};
static esp_err_t camera_init(void) {
#if CAM_PIN_PWDN >= 0
gpio_config_t pwdn_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(CAM_PIN_PWDN)
};
gpio_config(&pwdn_conf);
gpio_set_level(CAM_PIN_PWDN, 0);
#endif
esp_err_t ret = esp_camera_init(&camera_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "camera init failed!");
return ret;
}
return ESP_OK;
}
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_camera.h"
#include "esp_lcd_panel_io.h"
#define TAG "example"
void lcd_disp_init(void)
{
ESP_LOGI(TAG, "Initialize Intel 8080 bus");
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.clk_src = LCD_CLK_SRC_PLL240M,
.dc_gpio_num = 0,
.wr_gpio_num = 0,
.data_gpio_nums = {
0, 0, 0, 0, 0, 0, 0, 0
},
.bus_width = 8,
.max_transfer_bytes = 200 * 100 * sizeof(uint16_t),
.psram_trans_align = 64,
.sram_trans_align = 4
};
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = 0,
.pclk_hz = 10000000,
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1
},
.lcd_cmd_bits = 8,
.lcd_param_bits = 8
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
}
static camera_config_t camera_config = {
.pin_pwdn = 1,
.pin_reset = 1,
.pin_xclk = 1,
.pin_sccb_sda = 1,
.pin_sccb_scl = 2,
.pin_pclk = 1,
.pin_href = 1,
.pin_vsync = 1,
.pin_d7 = 1,
.pin_d6 = 1,
.pin_d5 = 1,
.pin_d4 = 1,
.pin_d3 = 1,
.pin_d2 = 1,
.pin_d1 = 1,
.pin_d0 = 1,
.xclk_freq_hz = 2000000,
.ledc_timer = 0,
.ledc_channel = 0,
.pixel_format = PIXFORMAT_RGB565,
.frame_size = FRAMESIZE_QVGA,
.jpeg_quality = 12, // 0-63, for OV series camera sensors, lower number means higher quality
.fb_count = 1, //When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode.
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};
void app_main(void)
{
lcd_disp_init();
ESP_ERROR_CHECK(esp_camera_init(&camera_config));
}
yes, I still can't see the issue with the above code. Please ignore the GPIO settings. I just want to test the esp_lcd_new_i80_bus
and esp_camera_init
can work at the same time because both of them will call esp_intr_alloc_intrstatus
LCD和Camera初始化冲突找到解决办法, 确实是配置中断的冲突, LCD和Camera中断用同一个中断源, 导致分配中断失败. 解决办法是LCD中断和Camera中断分配到不同的CPU. 比如LCD在CPU0 任务里初始化, Camera在CPU1任务里初始化. 另外发现必须先初始化Camera再初始化LCD, 否则还是有异常, 这个没发现什么原因.
目前LCD用80接口基本正常, 可以初始化成功, 摄像头实时采集并显示到LCD. 但是LCD用RGB接口, 可以初始化成功, 但是Camera采集失败, 提示Failed to get the frame on time!
Hi @liruya Thanks for keeping debug!
The camera will allocate the interrupt with ESP_INTR_FLAG_IRAM. But this is not the case for the RGB LCD driver. In the RGB LCD driver, we don't use that flag unless the Kconfig LCD_RGB_ISR_IRAM_SAFE
is enabled. That means, if you enabled that flag, then you can initialize the RGB LCD and camera driver from the same CPU core.
But I doubt if the camera should use ESP_INTR_FLAG_IRAM
in the first place. I will ask the camera author to evaluate this.
@suda-morris
If my understanding is correct: gpio_install_isr_service() only takes effect for the first call. (The second call will return ESP_ERR_INVALID_STATE, "GPIO isr service already installed")
I'm wondering what happened if 2 components that both have called gpio_install_isr_service() with different intr_alloc_flags. Isn't this racy?
For example, if I have code using examples/bluetooth/esp_ble_mesh/common_components/button/button.c which calls gpio_install_isr_service(0); I also use esp32-camera driver which calls gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM);
Then different call sequence has different intr_alloc_flags setting. And if any of the component calls gpio_uninstall_isr_service(), both components stop working?
CC @me-no-dev for the question in https://github.com/espressif/esp-idf/issues/12882#issuecomment-1899873402
There are two areas worth investigating:
@WangYuxin-esp thanks for the pointers!
@AxelLin please try https://github.com/espressif/esp32-camera/pull/629
@suda-morris the flag is there to help speed things up a bit. ESP32 needs it to convert I2S samples to actual data. I can make it optional for S2 and S3 with LCD_CAM_ISR_IRAM_SAFE
.
@AxelLin OK if I add it to the same PR for you to try?
@liruya Did you try esp32-camera v2.0.8? Is this still an issue?
Answers checklist.
General issue report
esp-idf版本5.1.2. ESP32S3 LCD用i80接口或者RGB接口, 同时使用Camera, 就会出现这种情况. 如果先初始化LCD, 则Camera初始化失败, 如果先初始化Camera, 则LCD初始化失败. 如果LCD用SPI接口, 则没有问题. 定位到 esp_intr_alloc_intrstatus -> get_available_int 这里, 中断配置失败. LCD和Camera的中断配置出现冲突, 不知道怎么解决.