diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 43f86e8c7d38..fad3c7ecb6e7 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BEETLE beetle_clock_control.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ADSP clock_control_adsp.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32 clock_control_esp32.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32_CAM clock_control_esp32_cam.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_control_fixed_rate.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LITEX clock_control_litex.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 558210560479..4a1fe1526506 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -56,6 +56,8 @@ source "drivers/clock_control/Kconfig.rv32m1" source "drivers/clock_control/Kconfig.esp32" +source "drivers/clock_control/Kconfig.esp32_cam" + source "drivers/clock_control/Kconfig.litex" source "drivers/clock_control/Kconfig.rcar" diff --git a/drivers/clock_control/Kconfig.esp32_cam b/drivers/clock_control/Kconfig.esp32_cam new file mode 100644 index 000000000000..f7b9b0e5861d --- /dev/null +++ b/drivers/clock_control/Kconfig.esp32_cam @@ -0,0 +1,4 @@ +config CLOCK_CONTROL_ESP32_CAM + bool "master clock for esp32 camera interface" + help + This option enables the pheriphery and cam clock for the lcd_cam module. diff --git a/drivers/clock_control/clock_control_esp32_cam.c b/drivers/clock_control/clock_control_esp32_cam.c new file mode 100644 index 000000000000..01524e279d62 --- /dev/null +++ b/drivers/clock_control/clock_control_esp32_cam.c @@ -0,0 +1,99 @@ +#define DT_DRV_COMPAT espressif_esp32_cam_clk + +#include +LOG_MODULE_REGISTER(esp32_lcd_cam, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#define ESP32_CAM_PLL_F160M 160000000UL +#define ESP32_CAM_PLL_F160M_SEL 3 +#define ESP32_CAM_CLK_OFF_SEL 0 + +struct clock_control_esp32_cam_config { + const struct pinctrl_dev_config *pcfg; + const struct device *clk_dev; + struct device *clk_subsys; + uint32_t cam_clk; + uint8_t clock_sel; +}; + +static int enable_pheripheral_clock(const struct device *dev) +{ + const struct clock_control_esp32_cam_config *cfg = dev->config; + int ret = 0; + + /* Enable peripheral */ + if (!device_is_ready(cfg->clk_dev)) { + return -ENODEV; + } + + return clock_control_on(cfg->clk_dev, cfg->clk_subsys); +} + +static int set_camera_clock(uint32_t cam_clk) +{ + int ret = 0; + + if (0 == cam_clk) { + LCD_CAM.cam_ctrl.cam_clk_sel = + ESP32_CAM_CLK_OFF_SEL; + LOG_DBG("Disabled CAM_CLK"); + return -EINVAL; + } + + if (ESP32_CAM_PLL_F160M % cam_clk) { + LOG_WRN("MCLK is not a devider of 160MHz"); + } + + LCD_CAM.cam_ctrl.cam_clk_sel = ESP32_CAM_PLL_F160M_SEL; + LCD_CAM.cam_ctrl.cam_clkm_div_num = ESP32_CAM_PLL_F160M / cam_clk; + LCD_CAM.cam_ctrl.cam_clkm_div_b = 0; + LCD_CAM.cam_ctrl.cam_clkm_div_a = 0; + LOG_DBG("MCLK set to %ld", ESP32_CAM_PLL_F160M / LCD_CAM.cam_ctrl.cam_clkm_div_num); + + return ret; +} + +static int clock_control_esp32_cam_init(const struct device *dev) +{ + const struct clock_control_esp32_cam_config *cfg = dev->config; + int ret = 0; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("video pinctrl setup failed (%d)", ret); + return ret; + } + + ret = enable_pheripheral_clock(dev); + if (ret < 0) { + LOG_ERR("Failed to enable peripheral clock"); + return ret; + } + + ret = set_camera_clock(cfg->cam_clk); + if (ret < 0) { + LOG_ERR("Failed to set camera clock"); + return ret; + } + + LOG_DBG("cam clock initialized"); + + return 0; +} + +PINCTRL_DT_INST_DEFINE(0); + +static const struct clock_control_esp32_cam_config clock_control_esp32_cam_config = { + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), + .clk_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(0, offset), + .cam_clk = DT_INST_PROP_OR(0, cam_clk, 0), +}; + +DEVICE_DT_INST_DEFINE(0, &clock_control_esp32_cam_init, NULL, NULL, &clock_control_esp32_cam_config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, NULL); diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 2e52d1f66ea8..2feae9ec6a8d 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_library_sources(video_common.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32S3 video_esp32_dvp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX video_mcux_mipi_csi2rx.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_SW_GENERATOR video_sw_generator.c) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d6a6bd3ccce6..8458695e143b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -31,6 +31,8 @@ config VIDEO_BUFFER_POOL_ALIGN int "Alignment of the video pool’s buffer" default 64 +source "drivers/video/Kconfig.esp32_dvp" + source "drivers/video/Kconfig.mcux_csi" source "drivers/video/Kconfig.mcux_mipi_csi2rx" diff --git a/drivers/video/Kconfig.esp32_dvp b/drivers/video/Kconfig.esp32_dvp new file mode 100644 index 000000000000..dc947a1c91e7 --- /dev/null +++ b/drivers/video/Kconfig.esp32_dvp @@ -0,0 +1,6 @@ +config VIDEO_ESP32S3 + bool "Video interface driver" + default n + depends on DMA + help + This option enables the video interface for the esp32s3. diff --git a/drivers/video/video_esp32_dvp.c b/drivers/video/video_esp32_dvp.c new file mode 100644 index 000000000000..98e698f5f1fa --- /dev/null +++ b/drivers/video/video_esp32_dvp.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2024 espros photonics Co. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_cam + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(esp32_cam, LOG_LEVEL_INF); + +#define VIDEO_ESP32_F160M 160000000UL +#define VIDEO_ESP32_DMA_BUFFER_MAX_SIZE 4095 + +enum video_esp32_cam_clk_sel_values { + VIDEO_ESP32_CAM_CLK_SEL_NONE = 0, + VIDEO_ESP32_CAM_CLK_SEL_XTAL = 1, + VIDEO_ESP32_CAM_CLK_SEL_PLL_DIV2 = 2, + VIDEO_ESP32_CAM_CLK_SEL_PLL_F160M = 3, +}; + +struct video_esp32_config { + const struct pinctrl_dev_config *pcfg; + const struct device *source_dev; + const struct device *clock_dev; + const clock_control_subsys_t clock_subsys; + const struct device *dma_dev; + uint8_t rx_dma_channel; + uint32_t clock_mclk; + int irq_source; + int irq_priority; + uint8_t data_width; + uint8_t vsync_filter; + uint8_t invert_de; + uint8_t invert_byte_order; + uint8_t invert_bit_order; + uint8_t invert_pclk; + uint8_t invert_hsync; + uint8_t invert_vsync; +}; + +struct video_esp32_data { + const struct video_esp32_config *config; + cam_hal_context_t cam_hal_context; + struct video_format video_format; + struct video_buffer *active_vbuf; + bool is_streaming; + struct k_fifo fifo_in; + struct k_fifo fifo_out; + struct dma_block_config dma_blocks[CONFIG_DMA_ESP32_MAX_DESCRIPTOR_NUM]; +}; + +static int video_esp32_reload_dma(struct video_esp32_data *data); + +void video_esp32_dma_rx_done(const struct device *dev, void *user_data, uint32_t channel, + int status) +{ + struct video_esp32_data *data = user_data; + int ret = 0; + + if (status == DMA_STATUS_BLOCK) { + LOG_DBG("received block"); + return; + } + + if (status != DMA_STATUS_COMPLETE) { + LOG_ERR("DMA error: %d", status); + return; + } + + if (data->active_vbuf == NULL) { + LOG_ERR("No video buffer available. Enque some buffers first."); + return; + } + + k_fifo_put(&data->fifo_out, data->active_vbuf); + data->active_vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT); + + if (data->active_vbuf == NULL) { + LOG_WRN("Frame dropped. No buffer available"); + return; + } + video_esp32_reload_dma(data); +} + +static int video_esp32_reload_dma(struct video_esp32_data *data) +{ + const struct video_esp32_config *cfg = data->config; + int ret = 0; + + if (data->active_vbuf == NULL) { + LOG_ERR("No video buffer available. Enque some buffers first."); + return -EAGAIN; + } + + ret = dma_reload(cfg->dma_dev, cfg->rx_dma_channel, 0, (uint32_t)data->active_vbuf->buffer, + data->active_vbuf->bytesused); + if (ret) { + LOG_ERR("Unable to reload DMA (%d)", ret); + return ret; + } + + ret = dma_start(cfg->dma_dev, cfg->rx_dma_channel); + if (ret) { + LOG_ERR("Unable to start DMA (%d)", ret); + return ret; + } + + return 0; +} + +static int video_esp32_stream_start(const struct device *dev) +{ + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + struct dma_status dma_status = {0}; + struct dma_config dma_cfg = {0}; + struct dma_block_config *dma_block_iter = data->dma_blocks; + uint32_t buffer_size = 0; + int error = 0; + + if (data->is_streaming) { + return -EBUSY; + } + + LOG_DBG("Start streaming"); + + error = dma_get_status(cfg->dma_dev, cfg->rx_dma_channel, &dma_status); + + if (error) { + LOG_ERR("Unable to get Rx status (%d)", error); + return error; + } + + if (dma_status.busy) { + LOG_ERR("Rx DMA Channel %d is busy", cfg->rx_dma_channel); + return -EBUSY; + } + + data->active_vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT); + if (!data->active_vbuf) { + LOG_ERR("No enqueued video buffers available."); + return -EAGAIN; + } + + buffer_size = data->active_vbuf->bytesused; + memset(data->dma_blocks, 0, sizeof(data->dma_blocks)); + for (size_t i = 0; i < CONFIG_DMA_ESP32_MAX_DESCRIPTOR_NUM; ++i) { + dma_block_iter->dest_address = + (uint32_t)data->active_vbuf->buffer + i * VIDEO_ESP32_DMA_BUFFER_MAX_SIZE; + if (buffer_size < VIDEO_ESP32_DMA_BUFFER_MAX_SIZE) { + dma_block_iter->block_size = buffer_size; + dma_block_iter->next_block = NULL; + dma_cfg.block_count = i + 1; + break; + } + dma_block_iter->block_size = VIDEO_ESP32_DMA_BUFFER_MAX_SIZE; + dma_block_iter->next_block = dma_block_iter + 1; + dma_block_iter++; + buffer_size -= VIDEO_ESP32_DMA_BUFFER_MAX_SIZE; + } + + if (dma_block_iter->next_block) { + LOG_ERR("Not enough descriptors available. Increase CONFIG_DMA_ESP32_MAX_DESCRIPTOR_NUM by %d", buffer_size / VIDEO_ESP32_DMA_BUFFER_MAX_SIZE+1); + return -ENOBUFS; + } + + dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY; + dma_cfg.dma_callback = video_esp32_dma_rx_done; + dma_cfg.user_data = data; + dma_cfg.dma_slot = SOC_GDMA_TRIG_PERIPH_CAM0; + dma_cfg.complete_callback_en = 1; + dma_cfg.head_block = &data->dma_blocks[0]; + + error = dma_config(cfg->dma_dev, cfg->rx_dma_channel, &dma_cfg); + if (error) { + LOG_ERR("Unable to configure DMA (%d)", error); + return error; + } + + error = dma_start(cfg->dma_dev, cfg->rx_dma_channel); + if (error) { + LOG_ERR("Unable to start DMA (%d)", error); + return error; + } + + cam_hal_start_streaming(&data->cam_hal_context); + + data->is_streaming = true; + + return 0; +} + +static int video_esp32_stream_stop(const struct device *dev) +{ + int ret = 0; + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + + LOG_DBG("Stop streaming"); + + data->is_streaming = false; + dma_stop(cfg->dma_dev, cfg->rx_dma_channel); + cam_hal_stop_streaming(&data->cam_hal_context); + return ret; +} + +static int video_esp32_get_caps(const struct device *dev, enum video_endpoint_id ep, + struct video_caps *caps) +{ + const struct video_esp32_config *config = dev->config; + int ret = -ENODEV; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + /* Forward the message to the source device */ + ret = video_get_caps(config->source_dev, ep, caps); + + return ret; +} + +static int video_esp32_get_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct video_esp32_config *cfg = dev->config; + int ret = 0; + + LOG_DBG("Get format"); + + if (fmt == NULL || ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + ret = video_get_format(cfg->source_dev, ep, fmt); + if (ret) { + LOG_ERR("Failed to get format from source"); + return ret; + } + + return ret; +} + +static int video_esp32_set_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + + if (fmt == NULL || ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + data->video_format = *fmt; + + return video_set_format(cfg->source_dev, ep, fmt); +} + +static int video_esp32_enqueue(const struct device *dev, enum video_endpoint_id ep, + struct video_buffer *vbuf) +{ + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + int ret = 0; + unsigned int key; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + vbuf->bytesused = data->video_format.pitch * data->video_format.height; + + k_fifo_put(&data->fifo_in, vbuf); + + return ret; +} + +static int video_esp32_dequeue(const struct device *dev, enum video_endpoint_id ep, + struct video_buffer **vbuf, k_timeout_t timeout) +{ + struct video_esp32_data *data = dev->data; + int ret = 0; + uint8_t key; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + *vbuf = k_fifo_get(&data->fifo_out, timeout); + LOG_DBG("Dequeue done, vbuf = %p", *vbuf); + if (*vbuf == NULL) { + return -EAGAIN; + } + + return 0; +} + +static int video_esp32_set_ctrl(const struct device *dev, unsigned int cid, void *value) +{ + const struct video_esp32_config *cfg = dev->config; + + return video_set_ctrl(cfg->source_dev, cid, value); +} + +static int video_esp32_get_ctrl(const struct device *dev, unsigned int cid, void *value) +{ + const struct video_esp32_config *cfg = dev->config; + + return video_get_ctrl(cfg->source_dev, cid, value); +} + +static void video_esp32_cam_ctrl_init(const struct device *dev) +{ + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + cam_dev_t *cam_dev; + + data->cam_hal_context.hw = CAM_LL_GET_HW(0); + cam_dev = data->cam_hal_context.hw; + + cam_ll_enable_stop_signal(cam_dev, 0); + cam_ll_swap_dma_data_byte_order(cam_dev, cfg->invert_byte_order); + cam_ll_reverse_dma_data_bit_order(cam_dev, cfg->invert_bit_order); + cam_ll_enable_vsync_generate_eof(cam_dev, 1); + + cam_ll_enable_hs_line_int(cam_dev, 0); + cam_ll_set_line_int_num(cam_dev, 0); + cam_ll_enable_vsync_filter(cam_dev, cfg->vsync_filter != 0); + cam_ll_set_vsync_filter_thres(cam_dev, cfg->vsync_filter); + + cam_ll_set_input_data_width(cam_dev, cfg->data_width); + cam_ll_enable_invert_pclk(cam_dev, cfg->invert_pclk); + cam_ll_enable_invert_de(cam_dev, cfg->invert_de); + cam_ll_enable_invert_vsync(cam_dev, cfg->invert_vsync); + cam_ll_enable_invert_hsync(cam_dev, cfg->invert_hsync); + cam_ll_set_vh_de_mode(cam_dev, 0); // Disable vh_de mode default + cam_ll_enable_rgb_yuv_convert(cam_dev, 0); // bypass conv module + +} + +static int esp32_init(const struct device *dev) +{ + const struct video_esp32_config *cfg = dev->config; + struct video_esp32_data *data = dev->data; + int ret = 0; + + data->config = cfg; + + k_fifo_init(&data->fifo_in); + k_fifo_init(&data->fifo_out); + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("video pinctrl setup failed (%d)", ret); + return ret; + } + + video_esp32_cam_ctrl_init(dev); + + if (!device_is_ready(cfg->dma_dev)) { + return -ENODEV; + } + + LOG_DBG("esp32 video driver loaded"); + + return ret; +} + +static const struct video_driver_api esp32_driver_api = { + /* mandatory callbacks */ + .set_format = video_esp32_set_fmt, + .get_format = video_esp32_get_fmt, + .stream_start = video_esp32_stream_start, + .stream_stop = video_esp32_stream_stop, + .get_caps = video_esp32_get_caps, + /* optional callbacks */ + .enqueue = video_esp32_enqueue, + .dequeue = video_esp32_dequeue, + .flush = NULL, + .set_ctrl = video_esp32_set_ctrl, + .get_ctrl = video_esp32_get_ctrl, + .set_signal = NULL, +}; + +PINCTRL_DT_INST_DEFINE(0); + +static const struct video_esp32_config esp32_config = { + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .source_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, source)), + .dma_dev = ESP32_DT_INST_DMA_CTLR(0, rx), + .rx_dma_channel = DT_INST_DMAS_CELL_BY_NAME(0, rx, channel), + .data_width = DT_INST_PROP(0, data_width), + .vsync_filter = DT_INST_PROP(0, vsync_filter), + .invert_bit_order = DT_INST_PROP(0, invert_bit_order), + .invert_byte_order = DT_INST_PROP(0, invert_byte_order), + .invert_pclk = DT_INST_PROP(0, invert_pclk), + .invert_de = DT_INST_PROP(0, invert_de), + .invert_hsync = DT_INST_PROP(0, invert_hsync), + .invert_vsync = DT_INST_PROP(0, invert_vsync)}; + +static struct video_esp32_data esp32_data = {0}; + +DEVICE_DT_INST_DEFINE(0, &esp32_init, PM_DEVICE_DT_INST_GET(idx), &esp32_data, &esp32_config, + POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &esp32_driver_api); diff --git a/dts/bindings/clock/espressif,esp32-cam-clk.yaml b/dts/bindings/clock/espressif,esp32-cam-clk.yaml new file mode 100644 index 000000000000..e4f534abd19e --- /dev/null +++ b/dts/bindings/clock/espressif,esp32-cam-clk.yaml @@ -0,0 +1,21 @@ +# +# Copyright (c) 2024 espros photonics Co. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: esp32 camera clock + +compatible: "espressif,esp32-cam-clk" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true + + cam_clk: + type: int diff --git a/dts/bindings/video/espressif,esp32-cam.yaml b/dts/bindings/video/espressif,esp32-cam.yaml new file mode 100644 index 000000000000..83a4c437963e --- /dev/null +++ b/dts/bindings/video/espressif,esp32-cam.yaml @@ -0,0 +1,51 @@ +# +# Copyright (c) 2024 espros photonics Co. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: esp32 camera interface + +compatible: "espressif,esp32-cam" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true + + source: + required: true + type: phandle + description: phandle of connected source device + + enable-16bit-mode: + type: boolean + description: enable 16bit interface + + invert-byte-order: + type: boolean + description: invert byte order in 16bit mode + + invert-bit-order: + type: boolean + description: invert bit order + + invert-pclk: + type: boolean + description: invert pixel clock signal + + invert-de: + type: boolean + description: invert data enable signal + + invert-hsync: + type: boolean + description: invert hsync signal + + invert-vsync: + type: boolean + description: invert vsync signal diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 2b571a659608..5de762111d41 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -323,6 +323,21 @@ status = "disabled"; }; + lcd_cam: lcd_cam@60041000 { + compatible = "espressif,esp32-cam-clk"; + reg = <0x60041000 DT_SIZE_K(4)>; + clocks = <&rtc ESP32_LCD_CAM_MODULE>; + status = "disabled"; + camera0: camera { + compatible = "espressif,esp32-cam"; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&dma 2>; + dma-names = "rx"; + status = "disabled"; + }; + }; + usb_serial: uart@60038000 { compatible = "espressif,esp32-usb-serial"; reg = <0x60038000 DT_SIZE_K(4)>; diff --git a/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.conf b/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.conf new file mode 100644 index 000000000000..d804d2f7c9c1 --- /dev/null +++ b/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.conf @@ -0,0 +1,5 @@ +CONFIG_DMA=y +CONFIG_VIDEO_ESP32S3=y +CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=40000 +CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3 +CONFIG_CLOCK_CONTROL_ESP32_CAM=y \ No newline at end of file diff --git a/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.overlay b/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.overlay new file mode 100644 index 000000000000..cde6569a8970 --- /dev/null +++ b/samples/drivers/video/capture/boards/xiao_esp32s3_procpu.overlay @@ -0,0 +1,85 @@ + #include + #include + #include + + / { + chosen { + zephyr_camera = &camera0; + }; + }; + +&dma { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + ov2640: ov2640@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + status = "okay"; + clock-rate-control = <0x80>; + port { + ov2640_ep_out: endpoint { + remote-endpoint = <&dvp_ep_in>; + }; + }; + }; +}; + +&lcd_cam { + status = "okay"; + cam_clk = < 10000000 >; + pinctrl-0 = <&lcd_cam_default>; + pinctrl-names = "default"; +}; + +&camera0 { + status = "okay"; + pinctrl-0 = <&cam_default>; + pinctrl-names = "default"; + source = <&ov2640>; + port { + dvp_ep_in: endpoint { + remote-endpoint = <&ov2640_ep_out>; + }; + }; +}; + +&pinctrl { + lcd_cam_default: lcd_cam_default{ + group1 { + pinmux = ; + output-enable; + }; + }; + cam_default: cam_default { + group1 { + pinmux = , + , + , + , + , + , + , + , + , + , + ; + input-enable; + bias-disable; + }; + }; + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + }; diff --git a/samples/drivers/video/capture/src/main.c b/samples/drivers/video/capture/src/main.c index 862dff287f7a..64fae79f7de5 100644 --- a/samples/drivers/video/capture/src/main.c +++ b/samples/drivers/video/capture/src/main.c @@ -144,6 +144,20 @@ int main(void) } #endif + fmt.width = 160; + fmt.height = 120; + fmt.pitch = fmt.width * 2; + fmt.pixelformat = VIDEO_PIX_FMT_RGB565; + + if(video_set_format(video_dev, VIDEO_EP_OUT, &fmt)){ + LOG_ERR("Unable to set format"); + return 0; + } + + printk("- Set format: %c%c%c%c %ux%u\n", (char)fmt.pixelformat, + (char)(fmt.pixelformat >> 8), (char)(fmt.pixelformat >> 16), + (char)(fmt.pixelformat >> 24), fmt.width, fmt.height); + /* Size to allocate for each buffer */ bsize = fmt.pitch * fmt.height;