diff --git a/driver/cam_hal.c b/driver/cam_hal.c index 44639a5..9603887 100644 --- a/driver/cam_hal.c +++ b/driver/cam_hal.c @@ -100,7 +100,7 @@ static void cam_task(void *arg) while (1) { xQueueReceive(cam_obj->event_queue, (void *)&cam_event, portMAX_DELAY); - //DBG_PIN_SET(1); + DBG_PIN_SET(1); switch (cam_obj->state) { case CAM_STATE_IDLE: { @@ -203,7 +203,7 @@ static void cam_task(void *arg) } break; } - //DBG_PIN_SET(0); + DBG_PIN_SET(0); } } @@ -315,7 +315,7 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint #if CONFIG_IDF_TARGET_ESP32 cam_obj->psram_mode = false; #else - cam_obj->psram_mode = !cam_obj->jpeg_mode; + cam_obj->psram_mode = !cam_obj->jpeg_mode && (config->xclk_freq_hz == 16000000); #endif cam_obj->frame_cnt = config->fb_count; cam_obj->width = resolution[frame_size].width; diff --git a/sensors/ov2640.c b/sensors/ov2640.c index 811023c..7632524 100755 --- a/sensors/ov2640.c +++ b/sensors/ov2640.c @@ -157,26 +157,37 @@ static int set_window(sensor_t *sensor, ov2640_sensor_mode_t mode, int offset_x, {0, 0} }; - c.pclk_auto = 0; - c.pclk_div = 8; - c.clk_2x = 0; - c.clk_div = 0; - - if(sensor->pixformat != PIXFORMAT_JPEG){ - c.pclk_auto = 1; + if (sensor->pixformat == PIXFORMAT_JPEG) { + c.clk_2x = 0; + c.clk_div = 0; + c.pclk_auto = 0; + c.pclk_div = 8; + if(mode == OV2640_MODE_UXGA) { + c.pclk_div = 12; + } + } else { +#if CONFIG_IDF_TARGET_ESP32 + c.clk_2x = 0; +#else + c.clk_2x = 1; +#endif c.clk_div = 7; + c.pclk_auto = 1; + c.pclk_div = 8; + if (mode == OV2640_MODE_CIF) { + c.clk_div = 3; + } else if(mode == OV2640_MODE_UXGA) { + c.pclk_div = 12; + } } + ESP_LOGI(TAG, "Set PLL: clk_2x: %u, clk_div: %u, pclk_auto: %u, pclk_div: %u", c.clk_2x, c.clk_div, c.pclk_auto, c.pclk_div); if (mode == OV2640_MODE_CIF) { regs = ov2640_settings_to_cif; - if(sensor->pixformat != PIXFORMAT_JPEG){ - c.clk_div = 3; - } } else if (mode == OV2640_MODE_SVGA) { regs = ov2640_settings_to_svga; } else { regs = ov2640_settings_to_uxga; - c.pclk_div = 12; } WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS); diff --git a/sensors/ov3660.c b/sensors/ov3660.c index 2de3e8c..3c86393 100755 --- a/sensors/ov3660.c +++ b/sensors/ov3660.c @@ -142,7 +142,7 @@ static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sy int PCLK = PLLCLK / 2 / ((pclk_manual && pclk_div)?pclk_div:1); int SYSCLK = PLLCLK / 4; - ESP_LOGD(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO*1000, PLLCLK, SYSCLK, PCLK); + ESP_LOGI(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO*1000, PLLCLK, SYSCLK, PCLK); return SYSCLK; } @@ -363,12 +363,16 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) ret = set_pll(sensor, false, 30, 1, 3, false, 0, true, 10); } } else { - if (framesize > FRAMESIZE_CIF) { - //10MHz SYSCLK and 10MHz PCLK (6.19 FPS) - ret = set_pll(sensor, false, 2, 1, 0, false, 0, true, 2); + //tuned for 16MHz XCLK + if (framesize > FRAMESIZE_HVGA) { + //8MHz SYSCLK and 8MHz PCLK (4.44 FPS) + ret = set_pll(sensor, false, 4, 1, 0, false, 2, true, 2); + } else if (framesize >= FRAMESIZE_QVGA) { + //16MHz SYSCLK and 8MHz PCLK (10.25 FPS) + ret = set_pll(sensor, false, 8, 1, 0, false, 2, true, 4); } else { - //25MHz SYSCLK and 10MHz PCLK (15.45 FPS) - ret = set_pll(sensor, false, 5, 1, 0, false, 0, true, 5); + //32MHz SYSCLK and 8MHz PCLK (17.77 FPS) + ret = set_pll(sensor, false, 8, 1, 0, false, 0, true, 8); } } diff --git a/sensors/ov5640.c b/sensors/ov5640.c index bbc1938..86cf1f2 100755 --- a/sensors/ov5640.c +++ b/sensors/ov5640.c @@ -196,7 +196,7 @@ static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sy unsigned int SYSCLK = PLL_CLK / 4; - ESP_LOGD(TAG, "Calculated XVCLK: %d Hz, REFIN: %u Hz, VCO: %u Hz, PLL_CLK: %u Hz, SYSCLK: %u Hz, PCLK: %u Hz", xclk, REFIN, VCO, PLL_CLK, SYSCLK, PCLK); + ESP_LOGI(TAG, "Calculated XVCLK: %d Hz, REFIN: %u Hz, VCO: %u Hz, PLL_CLK: %u Hz, SYSCLK: %u Hz, PCLK: %u Hz", xclk, REFIN, VCO, PLL_CLK, SYSCLK, PCLK); return SYSCLK; } @@ -441,10 +441,14 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) ret = set_pll(sensor, false, sys_mul, 4, 2, false, 2, true, 4); //Set PLL: bypass: 0, multiplier: sys_mul, sys_div: 4, pre_div: 2, root_2x: 0, pclk_root_div: 2, pclk_manual: 1, pclk_div: 4 } else { - //ret = set_pll(sensor, false, 10, 1, 1, false, 1, true, 4); - //Set PLL: bypass: 0, multiplier: 10, sys_div: 1, pre_div: 1, root_2x: 0, pclk_root_div: 1, pclk_manual: 1, pclk_div: 4 - ret = set_pll(sensor, false, 8, 1, 1, false, 1, true, 4); - //Set PLL: bypass: 0, multiplier: 8, sys_div: 1, pre_div: 1, root_2x: 0, pclk_root_div: 1, pclk_manual: 1, pclk_div: 4 + //ret = set_pll(sensor, false, 8, 1, 1, false, 1, true, 4); + if (framesize > FRAMESIZE_HVGA) { + ret = set_pll(sensor, false, 10, 1, 2, false, 1, true, 2); + } else if (framesize >= FRAMESIZE_QVGA) { + ret = set_pll(sensor, false, 8, 1, 1, false, 1, true, 4); + } else { + ret = set_pll(sensor, false, 20, 1, 1, false, 1, true, 8); + } } if (ret == 0) { diff --git a/target/esp32/ll_cam.c b/target/esp32/ll_cam.c index 8ea1455..4840878 100644 --- a/target/esp32/ll_cam.c +++ b/target/esp32/ll_cam.c @@ -15,6 +15,7 @@ #include #include #include "soc/i2s_struct.h" +#include "esp_idf_version.h" #if ESP_IDF_VERSION_MAJOR >= 4 #include "hal/gpio_ll.h" #else diff --git a/target/esp32s2/ll_cam.c b/target/esp32s2/ll_cam.c index 820a451..dee2dd9 100644 --- a/target/esp32s2/ll_cam.c +++ b/target/esp32s2/ll_cam.c @@ -249,10 +249,83 @@ uint8_t ll_cam_get_dma_align(cam_obj_t *cam) return 16 << I2S0.lc_conf.ext_mem_bk_size; } +static void ll_cam_calc_rgb_dma(cam_obj_t *cam){ + size_t node_max = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE / cam->dma_bytes_per_item; + size_t line_width = cam->width * cam->in_bytes_per_pixel; + size_t node_size = node_max; + size_t nodes_per_line = 1; + size_t lines_per_node = 1; + + // Calculate DMA Node Size so that it's divisable by or divisor of the line width + if(line_width >= node_max){ + // One or more nodes will be requied for one line + for(size_t i = node_max; i > 0; i=i-1){ + if ((line_width % i) == 0) { + node_size = i; + nodes_per_line = line_width / node_size; + break; + } + } + } else { + // One or more lines can fit into one node + for(size_t i = node_max; i > 0; i=i-1){ + if ((i % line_width) == 0) { + node_size = i; + lines_per_node = node_size / line_width; + while((cam->height % lines_per_node) != 0){ + lines_per_node = lines_per_node - 1; + node_size = lines_per_node * line_width; + } + break; + } + } + } + + ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u", + node_size * cam->dma_bytes_per_item, nodes_per_line, lines_per_node); + + cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item; + + if (cam->psram_mode) { + cam->dma_buffer_size = cam->recv_size * cam->dma_bytes_per_item; + cam->dma_half_buffer_cnt = 2; + cam->dma_half_buffer_size = cam->dma_buffer_size / cam->dma_half_buffer_cnt; + } else { + size_t dma_half_buffer_max = 16 * 1024 / cam->dma_bytes_per_item; + if (line_width > dma_half_buffer_max) { + ESP_LOGE(TAG, "Resolution too high"); + return; + } + + // Calculate minimum EOF size = max(mode_size, line_size) + size_t dma_half_buffer_min = node_size * nodes_per_line; + + // Calculate max EOF size divisable by node size + size_t dma_half_buffer = (dma_half_buffer_max / dma_half_buffer_min) * dma_half_buffer_min; + + // Adjust EOF size so that height will be divisable by the number of lines in each EOF + size_t lines_per_half_buffer = dma_half_buffer / line_width; + while((cam->height % lines_per_half_buffer) != 0){ + dma_half_buffer = dma_half_buffer - dma_half_buffer_min; + lines_per_half_buffer = dma_half_buffer / line_width; + } + + // Calculate DMA size + size_t dma_buffer_max = 2 * dma_half_buffer_max; + size_t dma_buffer_size = dma_buffer_max; + dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer; + + ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u", + dma_half_buffer_min * cam->dma_bytes_per_item, dma_half_buffer * cam->dma_bytes_per_item, lines_per_half_buffer, dma_buffer_size * cam->dma_bytes_per_item); + + cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item; + cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item; + cam->dma_half_buffer_cnt = cam->dma_buffer_size / cam->dma_half_buffer_size; + } +} + void ll_cam_dma_sizes(cam_obj_t *cam) { - int cnt = 0; - cam->dma_bytes_per_item = 1; if (cam->jpeg_mode) { cam->dma_half_buffer_cnt = 16; @@ -260,16 +333,7 @@ void ll_cam_dma_sizes(cam_obj_t *cam) cam->dma_half_buffer_size = cam->dma_buffer_size / cam->dma_half_buffer_cnt; cam->dma_node_buffer_size = cam->dma_half_buffer_size; } else { - cam->dma_buffer_size = cam->recv_size; - cam->dma_half_buffer_cnt = 2; - cam->dma_half_buffer_size = cam->dma_buffer_size / cam->dma_half_buffer_cnt; - - for (cnt = 0; cnt < LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE; cnt++) { // Find a divisible dma size - if ((cam->dma_half_buffer_size) % (LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - cnt) == 0) { - break; - } - } - cam->dma_node_buffer_size = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - cnt; + ll_cam_calc_rgb_dma(cam); } } diff --git a/target/esp32s3/ll_cam.c b/target/esp32s3/ll_cam.c index a737092..37dbba7 100644 --- a/target/esp32s3/ll_cam.c +++ b/target/esp32s3/ll_cam.c @@ -267,10 +267,82 @@ uint8_t ll_cam_get_dma_align(cam_obj_t *cam) return 16 << GDMA.in[cam->dma_num].conf1.in_ext_mem_bk_size; } -void ll_cam_dma_sizes(cam_obj_t *cam) -{ - int cnt = 0; +static void ll_cam_calc_rgb_dma(cam_obj_t *cam){ + size_t node_max = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE / cam->dma_bytes_per_item; + size_t line_width = cam->width * cam->in_bytes_per_pixel; + size_t node_size = node_max; + size_t nodes_per_line = 1; + size_t lines_per_node = 1; + + // Calculate DMA Node Size so that it's divisable by or divisor of the line width + if(line_width >= node_max){ + // One or more nodes will be requied for one line + for(size_t i = node_max; i > 0; i=i-1){ + if ((line_width % i) == 0) { + node_size = i; + nodes_per_line = line_width / node_size; + break; + } + } + } else { + // One or more lines can fit into one node + for(size_t i = node_max; i > 0; i=i-1){ + if ((i % line_width) == 0) { + node_size = i; + lines_per_node = node_size / line_width; + while((cam->height % lines_per_node) != 0){ + lines_per_node = lines_per_node - 1; + node_size = lines_per_node * line_width; + } + break; + } + } + } + + ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u", + node_size * cam->dma_bytes_per_item, nodes_per_line, lines_per_node); + + cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item; + + size_t dma_half_buffer_max = 16 * 1024 / cam->dma_bytes_per_item; + if (line_width > dma_half_buffer_max) { + ESP_LOGE(TAG, "Resolution too high"); + return; + } + + // Calculate minimum EOF size = max(mode_size, line_size) + size_t dma_half_buffer_min = node_size * nodes_per_line; + + // Calculate max EOF size divisable by node size + size_t dma_half_buffer = (dma_half_buffer_max / dma_half_buffer_min) * dma_half_buffer_min; + + // Adjust EOF size so that height will be divisable by the number of lines in each EOF + size_t lines_per_half_buffer = dma_half_buffer / line_width; + while((cam->height % lines_per_half_buffer) != 0){ + dma_half_buffer = dma_half_buffer - dma_half_buffer_min; + lines_per_half_buffer = dma_half_buffer / line_width; + } + + // Calculate DMA size + size_t dma_buffer_max = 2 * dma_half_buffer_max; + if (cam->psram_mode) { + dma_buffer_max = cam->recv_size / cam->dma_bytes_per_item; + } + size_t dma_buffer_size = dma_buffer_max; + if (!cam->psram_mode) { + dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer; + } + ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u", + dma_half_buffer_min * cam->dma_bytes_per_item, dma_half_buffer * cam->dma_bytes_per_item, lines_per_half_buffer, dma_buffer_size * cam->dma_bytes_per_item); + + cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item; + cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item; + cam->dma_half_buffer_cnt = cam->dma_buffer_size / cam->dma_half_buffer_size; +} + +void ll_cam_dma_sizes(cam_obj_t *cam) +{ cam->dma_bytes_per_item = 1; if (cam->jpeg_mode) { cam->dma_half_buffer_cnt = 16; @@ -278,22 +350,7 @@ void ll_cam_dma_sizes(cam_obj_t *cam) cam->dma_half_buffer_size = cam->dma_buffer_size / cam->dma_half_buffer_cnt; cam->dma_node_buffer_size = cam->dma_half_buffer_size; } else { - int max_cam_rec_data_bytelen = 16384; - for (cnt = 0; cnt < max_cam_rec_data_bytelen; cnt++) { - if (cam->recv_size % (max_cam_rec_data_bytelen - cnt) == 0) { - break; - } - } - cam->dma_buffer_size = cam->recv_size; - cam->dma_half_buffer_size = max_cam_rec_data_bytelen - cnt; - cam->dma_half_buffer_cnt = cam->dma_buffer_size / cam->dma_half_buffer_size; - - for (cnt = 0; cnt < LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE; cnt++) { // Find a divisible dma size - if ((cam->dma_half_buffer_size) % (LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - cnt) == 0) { - break; - } - } - cam->dma_node_buffer_size = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE - cnt; + ll_cam_calc_rgb_dma(cam); } } diff --git a/target/private_include/ll_cam.h b/target/private_include/ll_cam.h index 8140f16..ae75919 100644 --- a/target/private_include/ll_cam.h +++ b/target/private_include/ll_cam.h @@ -35,12 +35,17 @@ #include "freertos/task.h" #include "freertos/semphr.h" -#define DBG_PIN_NUM -1//7//26 -#if DBG_PIN_NUM >= 0 -#include "hal/gpio_ll.h" -#define DBG_PIN_SET(v) gpio_ll_set_level(&GPIO, DBG_PIN_NUM, v) +#define CAMERA_DBG_PIN_ENABLE 0 +#if CAMERA_DBG_PIN_ENABLE + #if CONFIG_IDF_TARGET_ESP32 + #define DBG_PIN_NUM 26 + #else + #define DBG_PIN_NUM 7 + #endif + #include "hal/gpio_ll.h" + #define DBG_PIN_SET(v) gpio_ll_set_level(&GPIO, DBG_PIN_NUM, v) #else -#define DBG_PIN_SET(v) + #define DBG_PIN_SET(v) #endif #define CAM_CHECK(a, str, ret) if (!(a)) { \