Add RGB888 support and adjust PLL for RGB and YUV
This commit is contained in:
@@ -842,6 +842,86 @@ static void IRAM_ATTR dma_filter_yuyv_highspeed(const dma_elem_t* src, lldesc_t*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR dma_filter_rgb888(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst)
|
||||||
|
{
|
||||||
|
size_t end = dma_desc->length / sizeof(dma_elem_t) / 4;
|
||||||
|
uint8_t lb, hb;
|
||||||
|
for (size_t i = 0; i < end; ++i) {
|
||||||
|
hb = src[0].sample1;
|
||||||
|
lb = src[0].sample2;
|
||||||
|
dst[0] = (lb & 0x1F) << 3;
|
||||||
|
dst[1] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[2] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[1].sample1;
|
||||||
|
lb = src[1].sample2;
|
||||||
|
dst[3] = (lb & 0x1F) << 3;
|
||||||
|
dst[4] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[5] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[2].sample1;
|
||||||
|
lb = src[2].sample2;
|
||||||
|
dst[6] = (lb & 0x1F) << 3;
|
||||||
|
dst[7] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[8] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[3].sample1;
|
||||||
|
lb = src[3].sample2;
|
||||||
|
dst[9] = (lb & 0x1F) << 3;
|
||||||
|
dst[10] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[11] = hb & 0xF8;
|
||||||
|
src += 4;
|
||||||
|
dst += 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR dma_filter_rgb888_highspeed(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst)
|
||||||
|
{
|
||||||
|
size_t end = dma_desc->length / sizeof(dma_elem_t) / 8;
|
||||||
|
uint8_t lb, hb;
|
||||||
|
for (size_t i = 0; i < end; ++i) {
|
||||||
|
hb = src[0].sample1;
|
||||||
|
lb = src[1].sample1;
|
||||||
|
dst[0] = (lb & 0x1F) << 3;
|
||||||
|
dst[1] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[2] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[2].sample1;
|
||||||
|
lb = src[3].sample1;
|
||||||
|
dst[3] = (lb & 0x1F) << 3;
|
||||||
|
dst[4] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[5] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[4].sample1;
|
||||||
|
lb = src[5].sample1;
|
||||||
|
dst[6] = (lb & 0x1F) << 3;
|
||||||
|
dst[7] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[8] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[6].sample1;
|
||||||
|
lb = src[7].sample1;
|
||||||
|
dst[9] = (lb & 0x1F) << 3;
|
||||||
|
dst[10] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[11] = hb & 0xF8;
|
||||||
|
|
||||||
|
src += 8;
|
||||||
|
dst += 12;
|
||||||
|
}
|
||||||
|
if ((dma_desc->length & 0x7) != 0) {
|
||||||
|
hb = src[0].sample1;
|
||||||
|
lb = src[1].sample1;
|
||||||
|
dst[0] = (lb & 0x1F) << 3;
|
||||||
|
dst[1] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[2] = hb & 0xF8;
|
||||||
|
|
||||||
|
hb = src[2].sample1;
|
||||||
|
lb = src[2].sample2;
|
||||||
|
dst[3] = (lb & 0x1F) << 3;
|
||||||
|
dst[4] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
|
dst[5] = hb & 0xF8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public Methods
|
* Public Methods
|
||||||
* */
|
* */
|
||||||
@@ -1013,6 +1093,17 @@ esp_err_t camera_init(const camera_config_t* config)
|
|||||||
}
|
}
|
||||||
s_state->in_bytes_per_pixel = 2; // camera sends YU/YV
|
s_state->in_bytes_per_pixel = 2; // camera sends YU/YV
|
||||||
s_state->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
|
s_state->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
|
||||||
|
} else if (pix_format == PIXFORMAT_RGB888) {
|
||||||
|
s_state->fb_size = s_state->width * s_state->height * 3;
|
||||||
|
if (is_hs_mode()) {
|
||||||
|
s_state->sampling_mode = SM_0A00_0B00;
|
||||||
|
s_state->dma_filter = &dma_filter_rgb888_highspeed;
|
||||||
|
} else {
|
||||||
|
s_state->sampling_mode = SM_0A0B_0C0D;
|
||||||
|
s_state->dma_filter = &dma_filter_rgb888;
|
||||||
|
}
|
||||||
|
s_state->in_bytes_per_pixel = 2; // camera sends RGB565
|
||||||
|
s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888
|
||||||
} else if (pix_format == PIXFORMAT_JPEG) {
|
} else if (pix_format == PIXFORMAT_JPEG) {
|
||||||
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID) {
|
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID) {
|
||||||
ESP_LOGE(TAG, "JPEG format is only supported for ov2640 and ov3660");
|
ESP_LOGE(TAG, "JPEG format is only supported for ov2640 and ov3660");
|
||||||
|
|||||||
@@ -130,9 +130,6 @@ typedef struct _sensor {
|
|||||||
|
|
||||||
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
||||||
int (*set_lenc) (sensor_t *sensor, int enable);
|
int (*set_lenc) (sensor_t *sensor, int enable);
|
||||||
|
|
||||||
// Advanced functions
|
|
||||||
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
|
|
||||||
} sensor_t;
|
} sensor_t;
|
||||||
|
|
||||||
// Resolution table (in camera.c)
|
// Resolution table (in camera.c)
|
||||||
|
|||||||
@@ -140,10 +140,10 @@ int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sys_div,
|
|||||||
|
|
||||||
int VCO = (xclk / 1000) * pll_multiplier * pll_root_div * 2 / pll_pre_div2x;
|
int VCO = (xclk / 1000) * pll_multiplier * pll_root_div * 2 / pll_pre_div2x;
|
||||||
int PLLCLK = pll_bypass?(xclk):(VCO * 1000 * 2 / pll_sys_div / pll_seld52x);
|
int PLLCLK = pll_bypass?(xclk):(VCO * 1000 * 2 / pll_sys_div / pll_seld52x);
|
||||||
int PCLK = PLLCLK / 2 / (pclk_manual?pclk_div:1);
|
int PCLK = PLLCLK / 2 / ((pclk_manual && pclk_div)?pclk_div:1);
|
||||||
int SYSCLK = PLLCLK / 4;
|
int SYSCLK = PLLCLK / 4;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO, PLLCLK, SYSCLK, PCLK);
|
ESP_LOGD(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO*1000, PLLCLK, SYSCLK, PCLK);
|
||||||
return SYSCLK;
|
return SYSCLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ static int set_pll(sensor_t *sensor, bool bypass, uint8_t multiplier, uint8_t sy
|
|||||||
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL1, multiplier & 0x1f);
|
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL1, multiplier & 0x1f);
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL2, 0x10 | (sys_div & 0xf0));
|
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL2, 0x10 | (sys_div & 0x0f));
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL3, (pre_div & 0x3) << 4 | seld5 | (root_2x?0x40:0x00));
|
ret = write_reg(sensor->slv_addr, SC_PLLS_CTRL3, (pre_div & 0x3) << 4 | seld5 | (root_2x?0x40:0x00));
|
||||||
@@ -192,7 +192,7 @@ static int reset(sensor_t *sensor)
|
|||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
ret = write_regs(sensor->slv_addr, sensor_default_regs);
|
ret = write_regs(sensor->slv_addr, sensor_default_regs);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ESP_LOGE(TAG, "Camera defaults loaded");
|
ESP_LOGD(TAG, "Camera defaults loaded");
|
||||||
ret = set_ae_level(sensor, 0);
|
ret = set_ae_level(sensor, 0);
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
@@ -214,6 +214,7 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PIXFORMAT_RGB565:
|
case PIXFORMAT_RGB565:
|
||||||
|
case PIXFORMAT_RGB888:
|
||||||
regs = sensor_fmt_rgb565;
|
regs = sensor_fmt_rgb565;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -226,6 +227,7 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
ESP_LOGE(TAG, "Unsupported pixformat: %u", pixformat);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +343,7 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
|||||||
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2050, 788);
|
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2050, 788);
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = write_addr_reg(sensor->slv_addr, X_OFFSET_H, 8, 0);
|
ret = write_addr_reg(sensor->slv_addr, X_OFFSET_H, 8, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,8 +368,13 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
|||||||
ret = set_pll(sensor, false, 30, 1, 3, false, 0, true, 10);
|
ret = set_pll(sensor, false, 30, 1, 3, false, 0, true, 10);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//8.33MHz SYSCLK and 8.33MHz PCLK (maybe try bypass?)
|
if (framesize > FRAMESIZE_CIF) {
|
||||||
ret = set_pll(sensor, false, 10, 2, 3, false, 0, true, 2);
|
//10MHz SYSCLK and 10MHz PCLK (6.19 FPS)
|
||||||
|
ret = set_pll(sensor, false, 2, 1, 0, false, 0, true, 2);
|
||||||
|
} else {
|
||||||
|
//25MHz SYSCLK and 10MHz PCLK (15.45 FPS)
|
||||||
|
ret = set_pll(sensor, false, 5, 1, 0, false, 0, true, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
@@ -904,11 +911,6 @@ static int init_status(sensor_t *sensor)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int x_set_reg(sensor_t *sensor, int reg, int mask, int value)
|
|
||||||
{
|
|
||||||
return set_reg_bits(sensor->slv_addr, reg, 0, mask, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ov3660_init(sensor_t *sensor)
|
int ov3660_init(sensor_t *sensor)
|
||||||
{
|
{
|
||||||
sensor->reset = reset;
|
sensor->reset = reset;
|
||||||
@@ -940,7 +942,5 @@ int ov3660_init(sensor_t *sensor)
|
|||||||
sensor->set_raw_gma = set_raw_gma_dsp;
|
sensor->set_raw_gma = set_raw_gma_dsp;
|
||||||
sensor->set_lenc = set_lenc_dsp;
|
sensor->set_lenc = set_lenc_dsp;
|
||||||
sensor->set_denoise = set_denoise;
|
sensor->set_denoise = set_denoise;
|
||||||
|
|
||||||
sensor->set_reg = x_set_reg;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user