mirror of
https://github.com/espressif/esp32-camera.git
synced 2025-07-15 01:03:46 +08:00
Adjust clocks and DMA for non-jpeg modes and enable EDMA only for 16MHz XCLK
This commit is contained in:
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||
#include "hal/gpio_ll.h"
|
||||
#else
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)) { \
|
||||
|
Reference in New Issue
Block a user