Merge branch 'feature/lcd_cam_dvp_driver_only_gen_clock' into 'master'

feat(esp_driver_cam): DVP driver supports only initializing the clock and XCLK pin to generate a clock for the external device

Closes IDF-13385

See merge request espressif/esp-idf!39837
This commit is contained in:
Dong Heng
2025-07-08 16:49:51 +08:00
3 changed files with 81 additions and 10 deletions

View File

@@ -26,7 +26,7 @@ extern "C" {
esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const esp_cam_ctlr_dvp_pin_config_t *pin);
/**
* @brief ESP CAM DVP output hardware clock
* @brief ESP CAM DVP output hardware clock, the function "esp_cam_ctlr_dvp_init" should be called first
*
* @param ctlr_id CAM DVP controller ID
* @param clk_src CAM DVP clock source
@@ -38,6 +38,24 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e
*/
esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src, uint32_t xclk_freq);
/**
* @brief Initialize ESP CAM DVP clock pin (other DVP GPIO pins excluded the clock pins will not be initialized)
* and hardware clock, then output clock signal with given frequency
*
* @note The function is implemented based on "esp_cam_ctlr_dvp_init" and "esp_cam_ctlr_dvp_output_clock",
* so calling "esp_cam_ctlr_dvp_init" and "esp_cam_ctlr_dvp_output_clock" is not required
*
* @param ctlr_id DVP controller ID
* @param pin DVP clock pin
* @param clk_src DVP clock source
* @param xclk_freq DVP clock frequency
*
* @return
* - ESP_OK on success
* - Others if failed
*/
esp_err_t esp_cam_ctlr_dvp_start_clock(int ctlr_id, gpio_num_t pin, cam_clock_source_t clk_src, uint32_t xclk_freq);
/**
* @brief ESP CAM DVP de-initialzie.
*

View File

@@ -45,14 +45,16 @@
#define ALIGN_UP_BY(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv) \
{ \
ret = esp_cam_ctlr_dvp_config_input_gpio(pin, sig, inv); \
if (ret != ESP_OK) { \
ESP_LOGE(TAG, "failed to configure pin=%d sig=%d", \
pin, sig); \
return ret; \
} \
#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv) \
{ \
if (pin != GPIO_NUM_NC) { \
ret = esp_cam_ctlr_dvp_config_input_gpio(pin, sig, inv); \
if (ret != ESP_OK) { \
ESP_LOGE(TAG, "failed to configure pin=%d sig=%d", \
pin, sig); \
return ret; \
} \
} \
}
typedef struct dvp_platform {
@@ -360,7 +362,7 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e
}
/**
* @brief ESP CAM DVP output hardware clock
* @brief ESP CAM DVP output hardware clock, the function "esp_cam_ctlr_dvp_init" should be called first
*
* @param ctlr_id CAM DVP controller ID
* @param clk_src CAM DVP clock source
@@ -383,15 +385,54 @@ esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src,
if ((src_clk_hz % xclk_freq) == 0) {
DVP_CAM_CLK_ATOMIC() {
// The camera sensors require precision without frequency and duty cycle jitter,
// so the fractional divisor can't be used.
cam_ll_set_group_clock_coeff(ctlr_id, src_clk_hz / xclk_freq, 0, 0);
};
ret = ESP_OK;
} else {
ESP_LOGE(TAG, "calculated frequency divider is not integer so clock isn't changed");
}
return ret;
}
/**
* @brief Initialize ESP CAM DVP clock pin (other DVP GPIO pins excluded the clock pins will not be initialized)
* and hardware clock, then output clock signal with given frequency
*
* @note The function is implemented based on "esp_cam_ctlr_dvp_init" and "esp_cam_ctlr_dvp_output_clock",
* so calling "esp_cam_ctlr_dvp_init" and "esp_cam_ctlr_dvp_output_clock" is not required
*
* @param ctlr_id DVP controller ID
* @param pin DVP clock pin
* @param clk_src DVP clock source
* @param xclk_freq DVP clock frequency
*
* @return
* - ESP_OK on success
* - Others if failed
*/
esp_err_t esp_cam_ctlr_dvp_start_clock(int ctlr_id, gpio_num_t pin, cam_clock_source_t clk_src, uint32_t xclk_freq)
{
esp_cam_ctlr_dvp_pin_config_t pin_config = {0};
pin_config.data_width = CAM_CTLR_DATA_WIDTH_8;
pin_config.vsync_io = GPIO_NUM_NC;
pin_config.de_io = GPIO_NUM_NC;
pin_config.pclk_io = GPIO_NUM_NC;
for (int i = 0; i < CAM_DVP_DATA_SIG_NUM; i++) {
pin_config.data_io[i] = GPIO_NUM_NC;
}
pin_config.xclk_io = pin;
ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_init(ctlr_id, clk_src, &pin_config), TAG, "failed to initialize DVP controller");
ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_output_clock(ctlr_id, clk_src, xclk_freq), TAG, "failed to output clock");
return ESP_OK;
}
/**
* @brief ESP CAM DVP de-initialzie.
*

View File

@@ -7,6 +7,7 @@
#include "sdkconfig.h"
#include "unity.h"
#include "esp_cam_ctlr_dvp.h"
#include "esp_private/esp_cam_dvp.h"
#include "esp_cam_ctlr.h"
TEST_CASE("TEST DVP driver allocation", "[DVP]")
@@ -171,3 +172,14 @@ TEST_CASE("TEST DVP driver intern/extern generate xclk", "[DVP]")
TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle));
TEST_ESP_OK(esp_cam_ctlr_del(handle));
}
TEST_CASE("TEST DVP driver only output xclk signal", "[DVP]")
{
TEST_ESP_OK(esp_cam_ctlr_dvp_start_clock(0, 20, CAM_CLK_SRC_DEFAULT, 20000000));
TEST_ESP_OK(esp_cam_ctlr_dvp_deinit(0));
#if CONFIG_IDF_TARGET_ESP32S3
TEST_ESP_OK(esp_cam_ctlr_dvp_start_clock(0, 20, CAM_CLK_SRC_PLL240M, 24000000));
TEST_ESP_OK(esp_cam_ctlr_dvp_deinit(0));
#endif
}