Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32S3 LCD 和 Camera同时使用出现冲突 (IDFGH-11787) #12882

Open
3 tasks done
liruya opened this issue Dec 28, 2023 · 11 comments
Open
3 tasks done

ESP32S3 LCD 和 Camera同时使用出现冲突 (IDFGH-11787) #12882

liruya opened this issue Dec 28, 2023 · 11 comments
Assignees
Labels
Status: Opened Issue is new

Comments

@liruya
Copy link

liruya commented Dec 28, 2023

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

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的中断配置出现冲突, 不知道怎么解决.

@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 28, 2023
@github-actions github-actions bot changed the title ESP32S3 LCD 和 Camera同时使用出现冲突 ESP32S3 LCD 和 Camera同时使用出现冲突 (IDFGH-11787) Dec 28, 2023
@suda-morris
Copy link
Collaborator

@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
Copy link
Author

liruya commented Dec 28, 2023

@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
Copy link
Author

liruya commented Dec 28, 2023

@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;
}

@suda-morris
Copy link
Collaborator

/*
 * 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

@liruya
Copy link
Author

liruya commented Jan 2, 2024

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!

@suda-morris
Copy link
Collaborator

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.

@AxelLin
Copy link
Contributor

AxelLin commented Jan 26, 2024

@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 #12882 (comment)

@WangYuxin-esp
Copy link
Collaborator

There are two areas worth investigating:

@me-no-dev
Copy link
Member

@WangYuxin-esp thanks for the pointers!

@AxelLin please try espressif/esp32-camera#629

@me-no-dev
Copy link
Member

@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?

@AxelLin
Copy link
Contributor

AxelLin commented Mar 21, 2024

@liruya Did you try esp32-camera v2.0.8? Is this still an issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Opened Issue is new
Projects
None yet
Development

No branches or pull requests

6 participants