mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add exposure control for all sensors (#292)
* Textual register cleanup. No functional changes. * Add exposure control support. You can now set the exposure for the camera in microseconds (versus an opaque unknown value previously). First, we have a new method called get_exposure_us() which will get the expsoure time in microseconds. This let's you determine what the auto exposure algorithm set the exposure time to. Second, the previously implmented set_auto_exposure() method which allows you to turn aec off and on accepts a exposure_us keyword argument when you turn aec off to manually control the exposure. The next commit will add support for other sensor types. * Cleanup register formatting. No functional changes. * Add exposure control support for the OV2640. Register access for this chip is a PITA. * Formatting Cleanup. No functional changes. * Add exposure control for ov9650. Just doing it for all sensors. * Add missing 2 factor. * Added exposure control for the MT9V034. * Add exposure control example. Works well on the OV7725.
This commit is contained in:
parent
c78a269f5a
commit
7be0a7a182
@ -95,6 +95,13 @@
|
||||
#define MT9V034_AGC_ENABLE (1 << 1)
|
||||
#define MT9V034_THERMAL_INFO (0xC1)
|
||||
|
||||
#define MT9V034_WINDOW_HEIGHT_A (0x03)
|
||||
#define MT9V034_WINDOW_WIDTH_A (0x04)
|
||||
#define MT9V034_HORIZONTAL_BLANKING_A (0x05)
|
||||
#define MT9V034_VERTICAL_BLANKING_A (0x06)
|
||||
#define MT9V034_COARSE_SHUTTER_WIDTH_TOTAL_A (0x0B)
|
||||
#define MT9V034_FINE_SHUTTER_WIDTH_TOTAL_A (0xD5)
|
||||
|
||||
static int reset(sensor_t *sensor)
|
||||
{
|
||||
// NOTE: TODO This doesn't reset register configuration.
|
||||
@ -199,9 +206,41 @@ static int set_auto_gain(sensor_t *sensor, int enable, int gain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure)
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us)
|
||||
{
|
||||
return 0;
|
||||
uint16_t reg, row_limit_0, row_limit_1, row_time_0, row_time_1;
|
||||
int ret = cambus_readw(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, ®);
|
||||
ret |= cambus_writew(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, (reg & (~MT9V034_AEC_ENABLE)) | ((enable != 0) & MT9V034_AEC_ENABLE));
|
||||
|
||||
if ((enable == 0) && (exposure_us >= 0)) {
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_WINDOW_HEIGHT_A, &row_limit_0);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_VERTICAL_BLANKING_A, &row_limit_1);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_WINDOW_WIDTH_A, &row_time_0);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_HORIZONTAL_BLANKING_A, &row_time_1);
|
||||
|
||||
int exposure = exposure_us * (27000000 / 1000000);
|
||||
int row_time = row_time_0 + row_time_1;
|
||||
int coarse_time = IM_MIN((exposure / row_time), (row_limit_0 + row_limit_1));
|
||||
int fine_time = exposure % row_time;
|
||||
|
||||
ret |= cambus_writew(sensor->slv_addr, MT9V034_COARSE_SHUTTER_WIDTH_TOTAL_A, coarse_time);
|
||||
ret |= cambus_writew(sensor->slv_addr, MT9V034_FINE_SHUTTER_WIDTH_TOTAL_A, fine_time);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_exposure_us(sensor_t *sensor, int *exposure_us)
|
||||
{
|
||||
uint16_t int_rows, int_pixels, row_time_0, row_time_1;
|
||||
int ret = cambus_readw(sensor->slv_addr, MT9V034_COARSE_SHUTTER_WIDTH_TOTAL_A, &int_rows);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_FINE_SHUTTER_WIDTH_TOTAL_A, &int_pixels);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_WINDOW_WIDTH_A, &row_time_0);
|
||||
ret |= cambus_readw(sensor->slv_addr, MT9V034_HORIZONTAL_BLANKING_A, &row_time_1);
|
||||
|
||||
*exposure_us = ((int_rows * (row_time_0 + row_time_1)) + int_pixels) / (27000000 / 1000000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_auto_whitebal(sensor_t *sensor, int enable, int r_gain, int g_gain, int b_gain)
|
||||
@ -229,7 +268,6 @@ static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mt9v034_init(sensor_t *sensor)
|
||||
{
|
||||
// Initialize sensor structure.
|
||||
@ -248,6 +286,7 @@ int mt9v034_init(sensor_t *sensor)
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_auto_gain = set_auto_gain;
|
||||
sensor->set_auto_exposure = set_auto_exposure;
|
||||
sensor->get_exposure_us = get_exposure_us;
|
||||
sensor->set_auto_whitebal = set_auto_whitebal;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "ov2640.h"
|
||||
#include "systick.h"
|
||||
#include "ov2640_regs.h"
|
||||
#include "omv_boardconfig.h"
|
||||
|
||||
#define SVGA_HSIZE (800)
|
||||
#define SVGA_VSIZE (600)
|
||||
@ -619,22 +620,96 @@ static int set_auto_gain(sensor_t *sensor, int enable, int gain)
|
||||
return cambus_writeb(sensor->slv_addr, COM8, reg) | ret;
|
||||
}
|
||||
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure)
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us)
|
||||
{
|
||||
uint8_t reg;
|
||||
/* Switch to SENSOR register bank */
|
||||
int ret = cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR);
|
||||
|
||||
/* Update COM8 */
|
||||
int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR);
|
||||
ret |= cambus_readb(sensor->slv_addr, COM8, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, (enable != 0)));
|
||||
|
||||
if (enable) {
|
||||
reg |= COM8_AEC_EN;
|
||||
} else {
|
||||
reg &= ~COM8_AEC_EN;
|
||||
if ((enable == 0) && (exposure_us >= 0)) {
|
||||
ret |= cambus_readb(sensor->slv_addr, COM7, ®);
|
||||
int t_line = 0;
|
||||
|
||||
if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
|
||||
if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
|
||||
if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, CLKRC, ®);
|
||||
int pll_mult = (reg & CLKRC_DOUBLE) ? 2 : 1;
|
||||
int clk_rc = ((reg & CLKRC_DIVIDER_MASK) + 1) * 2;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR));
|
||||
ret |= cambus_readb(sensor->slv_addr, IMAGE_MODE, ®);
|
||||
int t_pclk = 0;
|
||||
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
|
||||
|
||||
int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000);
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR);
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG04, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG04, (reg & 0xFC) | ((exposure >> 0) & 0x3));
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, AEC, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, AEC, (reg & 0x00) | ((exposure >> 2) & 0xFF));
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG04, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG04, (reg & 0xC0) | ((exposure >> 10) & 0x3F));
|
||||
}
|
||||
|
||||
return cambus_writeb(sensor->slv_addr, COM8, reg) | ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_exposure_us(sensor_t *sensor, int *exposure_us)
|
||||
{
|
||||
uint8_t reg, aec_10, aec_92, aec_1510;
|
||||
int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR);
|
||||
ret |= cambus_readb(sensor->slv_addr, COM8, ®);
|
||||
|
||||
if (reg & COM8_AEC_EN) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, reg & (~COM8_AEC_EN));
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG04, &aec_10);
|
||||
ret |= cambus_readb(sensor->slv_addr, AEC, &aec_92);
|
||||
ret |= cambus_readb(sensor->slv_addr, REG45, &aec_1510);
|
||||
|
||||
if (reg & COM8_AEC_EN) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, reg | COM8_AEC_EN);
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, COM7, ®);
|
||||
int t_line = 0;
|
||||
|
||||
if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
|
||||
if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
|
||||
if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, CLKRC, ®);
|
||||
int pll_mult = (reg & CLKRC_DOUBLE) ? 2 : 1;
|
||||
int clk_rc = ((reg & CLKRC_DIVIDER_MASK) + 1) * 2;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR));
|
||||
ret |= cambus_readb(sensor->slv_addr, IMAGE_MODE, ®);
|
||||
int t_pclk = 0;
|
||||
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
|
||||
if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
|
||||
|
||||
uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0);
|
||||
*exposure_us = (exposure*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_auto_whitebal(sensor_t *sensor, int enable, int r_gain, int g_gain, int b_gain)
|
||||
@ -708,6 +783,7 @@ int ov2640_init(sensor_t *sensor)
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_auto_gain = set_auto_gain;
|
||||
sensor->set_auto_exposure = set_auto_exposure;
|
||||
sensor->get_exposure_us = get_exposure_us;
|
||||
sensor->set_auto_whitebal = set_auto_whitebal;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
@ -5,61 +5,64 @@
|
||||
*
|
||||
* OV2640 register definitions.
|
||||
*/
|
||||
|
||||
#ifndef __REG_REGS_H__
|
||||
#define __REG_REGS_H__
|
||||
|
||||
/* DSP register bank FF=0x00*/
|
||||
#define QS 0x44
|
||||
#define HSIZE 0x51
|
||||
#define VSIZE 0x52
|
||||
#define XOFFL 0x53
|
||||
#define YOFFL 0x54
|
||||
#define VHYX 0x55
|
||||
#define DPRP 0x56
|
||||
#define TEST 0x57
|
||||
#define ZMOW 0x5A
|
||||
#define ZMOH 0x5B
|
||||
#define ZMHH 0x5C
|
||||
#define BPADDR 0x7C
|
||||
#define BPDATA 0x7D
|
||||
#define SIZEL 0x8C
|
||||
#define HSIZE8 0xC0
|
||||
#define VSIZE8 0xC1
|
||||
#define CTRL1 0xC3
|
||||
#define MS_SP 0xF0
|
||||
#define SS_ID 0xF7
|
||||
#define SS_CTRL 0xF7
|
||||
#define MC_AL 0xFA
|
||||
#define MC_AH 0xFB
|
||||
#define MC_D 0xFC
|
||||
#define P_CMD 0xFD
|
||||
#define P_STATUS 0xFE
|
||||
|
||||
#define CTRLI 0x50
|
||||
#define CTRLI_LP_DP 0x80
|
||||
#define CTRLI_ROUND 0x40
|
||||
#define QS 0x44
|
||||
#define HSIZE 0x51
|
||||
#define VSIZE 0x52
|
||||
#define XOFFL 0x53
|
||||
#define YOFFL 0x54
|
||||
#define VHYX 0x55
|
||||
#define DPRP 0x56
|
||||
#define TEST 0x57
|
||||
#define ZMOW 0x5A
|
||||
#define ZMOH 0x5B
|
||||
#define ZMHH 0x5C
|
||||
#define BPADDR 0x7C
|
||||
#define BPDATA 0x7D
|
||||
#define SIZEL 0x8C
|
||||
#define HSIZE8 0xC0
|
||||
#define VSIZE8 0xC1
|
||||
#define CTRL1 0xC3
|
||||
#define MS_SP 0xF0
|
||||
#define SS_ID 0xF7
|
||||
#define SS_CTRL 0xF7
|
||||
#define MC_AL 0xFA
|
||||
#define MC_AH 0xFB
|
||||
#define MC_D 0xFC
|
||||
#define P_CMD 0xFD
|
||||
#define P_STATUS 0xFE
|
||||
|
||||
#define CTRL0 0xC2
|
||||
#define CTRL0_AEC_EN 0x80
|
||||
#define CTRL0_AEC_SEL 0x40
|
||||
#define CTRL0_STAT_SEL 0x20
|
||||
#define CTRL0_VFIRST 0x10
|
||||
#define CTRL0_YUV422 0x08
|
||||
#define CTRL0_YUV_EN 0x04
|
||||
#define CTRL0_RGB_EN 0x02
|
||||
#define CTRL0_RAW_EN 0x01
|
||||
#define CTRLI 0x50
|
||||
#define CTRLI_LP_DP 0x80
|
||||
#define CTRLI_ROUND 0x40
|
||||
|
||||
#define CTRL2 0x86
|
||||
#define CTRL2_DCW_EN 0x20
|
||||
#define CTRL2_SDE_EN 0x10
|
||||
#define CTRL2_UV_ADJ_EN 0x08
|
||||
#define CTRL2_UV_AVG_EN 0x04
|
||||
#define CTRL2_CMX_EN 0x01
|
||||
#define CTRL0 0xC2
|
||||
#define CTRL0_AEC_EN 0x80
|
||||
#define CTRL0_AEC_SEL 0x40
|
||||
#define CTRL0_STAT_SEL 0x20
|
||||
#define CTRL0_VFIRST 0x10
|
||||
#define CTRL0_YUV422 0x08
|
||||
#define CTRL0_YUV_EN 0x04
|
||||
#define CTRL0_RGB_EN 0x02
|
||||
#define CTRL0_RAW_EN 0x01
|
||||
|
||||
#define CTRL3 0x87
|
||||
#define CTRL3_BPC_EN 0x80
|
||||
#define CTRL3_WPC_EN 0x40
|
||||
#define R_DVP_SP 0xD3
|
||||
#define R_DVP_SP_AUTO_MODE 0x80
|
||||
#define CTRL2 0x86
|
||||
#define CTRL2_DCW_EN 0x20
|
||||
#define CTRL2_SDE_EN 0x10
|
||||
#define CTRL2_UV_ADJ_EN 0x08
|
||||
#define CTRL2_UV_AVG_EN 0x04
|
||||
#define CTRL2_CMX_EN 0x01
|
||||
|
||||
#define CTRL3 0x87
|
||||
#define CTRL3_BPC_EN 0x80
|
||||
#define CTRL3_WPC_EN 0x40
|
||||
#define R_DVP_SP 0xD3
|
||||
#define R_DVP_SP_AUTO_MODE 0x80
|
||||
|
||||
#define R_BYPASS 0x05
|
||||
#define R_BYPASS_DSP_EN 0x00
|
||||
@ -73,6 +76,7 @@
|
||||
#define IMAGE_MODE_RGB565 0x08
|
||||
#define IMAGE_MODE_HREF_VSYNC 0x02
|
||||
#define IMAGE_MODE_LBYTE_FIRST 0x01
|
||||
#define IMAGE_MODE_GET_FMT(x) ((x)&0xC)
|
||||
|
||||
#define RESET 0xE0
|
||||
#define RESET_MICROC 0x40
|
||||
@ -98,13 +102,18 @@
|
||||
#define BANK_SEL_SENSOR 0x01
|
||||
|
||||
/* Sensor register bank FF=0x01*/
|
||||
|
||||
#define GAIN 0x00
|
||||
#define COM1 0x03
|
||||
#define REG_PID 0x0A
|
||||
#define REG_VER 0x0B
|
||||
#define COM4 0x0D
|
||||
#define AEC 0x10
|
||||
|
||||
#define CLKRC 0x11
|
||||
#define CLKRC_DOUBLE 0x80
|
||||
#define CLKRC_DIVIDER_MASK 0x3F
|
||||
|
||||
#define COM10 0x15
|
||||
#define HSTART 0x17
|
||||
#define HSTOP 0x18
|
||||
@ -168,6 +177,7 @@
|
||||
#define COM7_RES_CIF 0x20 /* CIF */
|
||||
#define COM7_ZOOM_EN 0x04 /* Enable Zoom */
|
||||
#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */
|
||||
#define COM7_GET_RES(x) ((x)&0x70)
|
||||
|
||||
#define COM8 0x13
|
||||
#define COM8_DEFAULT 0xC0
|
||||
@ -175,6 +185,7 @@
|
||||
#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
|
||||
#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
|
||||
#define COM8_SET(x) (COM8_DEFAULT|x)
|
||||
#define COM8_SET_AEC(r,x) (((r)&0xFE)|((x)&1))
|
||||
|
||||
#define COM9 0x14 /* AGC gain ceiling */
|
||||
#define COM9_DEFAULT 0x08
|
||||
@ -196,4 +207,5 @@
|
||||
#define REG32_UXGA 0x36
|
||||
#define REG32_SVGA 0x09
|
||||
#define REG32_CIF 0x00
|
||||
|
||||
#endif //__REG_REGS_H__
|
||||
|
||||
@ -369,24 +369,87 @@ static int set_auto_gain(sensor_t *sensor, int enable, int gain)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure)
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us)
|
||||
{
|
||||
uint8_t reg;
|
||||
int ret = cambus_readb(sensor->slv_addr, COM8, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, (enable != 0)));
|
||||
|
||||
// Set AEC on/off
|
||||
reg = COM8_SET_AEC(reg, enable);
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, reg);
|
||||
if ((enable == 0) && (exposure_us >= 0)) {
|
||||
ret |= cambus_readb(sensor->slv_addr, COM7, ®);
|
||||
|
||||
if (enable == 0 && exposure >= 0) {
|
||||
// Set value manually.
|
||||
ret |= cambus_writeb(sensor->slv_addr, AEC, (exposure&0xFF));
|
||||
ret |= cambus_writeb(sensor->slv_addr, AECH, ((exposure>>8)&0xFF));
|
||||
int t_line = (reg & COM7_RES_QVGA) ? (320 + 256) : (640 + 144);
|
||||
int t_pclk = (COM7_GET_FMT(reg) == COM7_FMT_P_BAYER) ? 1 : 2;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, COM4, ®);
|
||||
int pll_mult = 0;
|
||||
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_BYPASS) pll_mult = 1;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_4x) pll_mult = 4;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_6x) pll_mult = 6;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_8x) pll_mult = 8;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, CLKRC, ®);
|
||||
int clk_rc = 0;
|
||||
|
||||
if (reg & CLKRC_NO_PRESCALE) {
|
||||
clk_rc = 1;
|
||||
} else {
|
||||
clk_rc = ((reg & CLKRC_PRESCALER) + 1) * 2;
|
||||
}
|
||||
|
||||
int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000);
|
||||
|
||||
ret |= cambus_writeb(sensor->slv_addr, AEC, ((exposure >> 0) & 0xFF));
|
||||
ret |= cambus_writeb(sensor->slv_addr, AECH, ((exposure >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_exposure_us(sensor_t *sensor, int *exposure_us)
|
||||
{
|
||||
uint8_t reg, aec_l, aec_h;
|
||||
int ret = cambus_readb(sensor->slv_addr, COM8, ®);
|
||||
|
||||
if (reg & COM8_AEC_EN) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, 0));
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, AEC, &aec_l);
|
||||
ret |= cambus_readb(sensor->slv_addr, AECH, &aec_h);
|
||||
|
||||
if (reg & COM8_AEC_EN) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, 1));
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, COM7, ®);
|
||||
|
||||
int t_line = (reg & COM7_RES_QVGA) ? (320 + 256) : (640 + 144);
|
||||
int t_pclk = (COM7_GET_FMT(reg) == COM7_FMT_P_BAYER) ? 1 : 2;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, COM4, ®);
|
||||
int pll_mult = 0;
|
||||
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_BYPASS) pll_mult = 1;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_4x) pll_mult = 4;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_6x) pll_mult = 6;
|
||||
if (COM4_GET_PLL(reg) == COM4_PLL_8x) pll_mult = 8;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, CLKRC, ®);
|
||||
int clk_rc = 0;
|
||||
|
||||
if (reg & CLKRC_NO_PRESCALE) {
|
||||
clk_rc = 1;
|
||||
} else {
|
||||
clk_rc = ((reg & CLKRC_PRESCALER) + 1) * 2;
|
||||
}
|
||||
|
||||
*exposure_us = (((aec_h<<8)+(aec_l<<0))*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_auto_whitebal(sensor_t *sensor, int enable, int r_gain, int g_gain, int b_gain)
|
||||
{
|
||||
uint8_t reg;
|
||||
@ -457,7 +520,6 @@ static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ov7725_init(sensor_t *sensor)
|
||||
{
|
||||
// Initialize sensor structure.
|
||||
@ -476,6 +538,7 @@ int ov7725_init(sensor_t *sensor)
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_auto_gain = set_auto_gain;
|
||||
sensor->set_auto_exposure = set_auto_exposure;
|
||||
sensor->get_exposure_us = get_exposure_us;
|
||||
sensor->set_auto_whitebal = set_auto_whitebal;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
@ -3,18 +3,20 @@
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OV2640 register definitions.
|
||||
* OV7725 register definitions.
|
||||
*/
|
||||
|
||||
#ifndef __REG_REGS_H__
|
||||
#define __REG_REGS_H__
|
||||
#define GAIN 0x00 /* AGC – Gain control gain setting */
|
||||
#define BLUE 0x01 /* AWB – Blue channel gain setting */
|
||||
#define RED 0x02 /* AWB – Red channel gain setting */
|
||||
#define GREEN 0x03 /* AWB – Green channel gain setting */
|
||||
#define BAVG 0x05 /* U/B Average Level */
|
||||
#define GAVG 0x06 /* Y/Gb Average Level */
|
||||
#define RAVG 0x07 /* V/R Average Level */
|
||||
#define AECH 0x08 /* Exposure Value – AEC MSBs */
|
||||
|
||||
#define GAIN 0x00 /* AGC - Gain control gain setting */
|
||||
#define BLUE 0x01 /* AWB - Blue channel gain setting */
|
||||
#define RED 0x02 /* AWB - Red channel gain setting */
|
||||
#define GREEN 0x03 /* AWB - Green channel gain setting */
|
||||
#define BAVG 0x05 /* U/B Average Level */
|
||||
#define GAVG 0x06 /* Y/Gb Average Level */
|
||||
#define RAVG 0x07 /* V/R Average Level */
|
||||
#define AECH 0x08 /* Exposure Value - AEC MSBs */
|
||||
|
||||
#define COM2 0x09 /* Common Control 2 */
|
||||
#define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */
|
||||
@ -26,28 +28,32 @@
|
||||
#define PID 0x0A /* Product ID Number MSB */
|
||||
#define VER 0x0B /* Product ID Number LSB */
|
||||
|
||||
#define COM3 0x0C /* Common Control 3 */
|
||||
#define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */
|
||||
#define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */
|
||||
#define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */
|
||||
#define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */
|
||||
#define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */
|
||||
#define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */
|
||||
#define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */
|
||||
#define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */
|
||||
#define COM3 0x0C /* Common Control 3 */
|
||||
#define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */
|
||||
#define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */
|
||||
#define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */
|
||||
#define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */
|
||||
#define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */
|
||||
#define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */
|
||||
#define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */
|
||||
#define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */
|
||||
#define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0))
|
||||
#define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6))
|
||||
#define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7))
|
||||
#define COM3_GET_CBAR(r) ((r>>0)&1)
|
||||
#define COM3_GET_MIRROR(r) ((r>>6)&1)
|
||||
#define COM3_GET_FLIP(r) ((r>>7)&1)
|
||||
|
||||
#define COM4 0x0D /* Common Control 4 */
|
||||
#define COM4_PLL_BYPASS 0x00 /* Bypass PLL */
|
||||
#define COM4_PLL_4x 0x40 /* PLL frequency 4x */
|
||||
#define COM4_PLL_6x 0x80 /* PLL frequency 6x */
|
||||
#define COM4_PLL_8x 0xc0 /* PLL frequency 8x */
|
||||
#define COM4_PLL_8x 0xC0 /* PLL frequency 8x */
|
||||
#define COM4_AEC_FULL 0x00 /* AEC evaluate full window */
|
||||
#define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */
|
||||
#define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */
|
||||
#define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */
|
||||
#define COM4_GET_PLL(r) (r&0xC0)
|
||||
|
||||
#define COM5 0x0E /* Common Control 5 */
|
||||
#define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */
|
||||
@ -65,7 +71,10 @@
|
||||
#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */
|
||||
|
||||
#define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */
|
||||
|
||||
#define CLKRC 0x11 /* Internal Clock */
|
||||
#define CLKRC_NO_PRESCALE 0x40 /* Use external clock directly */
|
||||
#define CLKRC_PRESCALER 0x3F /* Internal clock pre-scaler */
|
||||
|
||||
#define COM7 0x12 /* Common Control 7 */
|
||||
#define COM7_RESET 0x80 /* SCCB Register Reset */
|
||||
@ -83,9 +92,10 @@
|
||||
#define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */
|
||||
#define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0))
|
||||
#define COM7_SET_RES(r, x) ((r&0xBF)|(x))
|
||||
#define COM7_GET_FMT(r) (r&0x03)
|
||||
|
||||
#define COM8 0x13 /* Common Control 8 */
|
||||
#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */
|
||||
#define COM8 0x13 /* Common Control 8 */
|
||||
#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */
|
||||
#define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */
|
||||
#define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */
|
||||
#define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */
|
||||
@ -124,13 +134,14 @@
|
||||
|
||||
#define REG16 0x16 /* Register 16 */
|
||||
#define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */
|
||||
|
||||
#define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */
|
||||
#define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */
|
||||
#define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */
|
||||
#define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */
|
||||
#define PSHFT 0x1B /* Data Format - Pixel Delay Select */
|
||||
#define MIDH 0x1C /* Manufacturer ID Byte – High */
|
||||
#define MIDL 0x1D /* Manufacturer ID Byte – Low */
|
||||
#define MIDH 0x1C /* Manufacturer ID Byte - High */
|
||||
#define MIDL 0x1D /* Manufacturer ID Byte - Low */
|
||||
#define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */
|
||||
|
||||
#define COM11 0x20 /* Common Control 11 */
|
||||
@ -146,8 +157,8 @@
|
||||
#define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */
|
||||
#define EXHCH 0x2A /* Dummy Pixel Insert MSB */
|
||||
#define EXHCL 0x2B /* Dummy Pixel Insert LSB */
|
||||
#define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */
|
||||
#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */
|
||||
#define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */
|
||||
#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */
|
||||
#define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */
|
||||
#define YAVE 0x2F /* Y/G Channel Average Value */
|
||||
#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */
|
||||
@ -163,6 +174,7 @@
|
||||
#define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */
|
||||
#define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */
|
||||
#define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */
|
||||
|
||||
#define COM12 0x3D /* DC offset compensation for analog process */
|
||||
|
||||
#define COM13 0x3E /* Common Control 13 */
|
||||
@ -174,10 +186,10 @@
|
||||
#define COM14 0x3F /* Common Control 14 */
|
||||
#define COM15 0x40 /* Common Control 15 */
|
||||
#define COM16 0x41 /* Common Control 16 */
|
||||
#define TGT_B 0x42 /* BLC Blue Channel Target Value */
|
||||
#define TGT_R 0x43 /* BLC Red Channel Target Value */
|
||||
#define TGT_GB 0x44 /* BLC Gb Channel Target Value */
|
||||
#define TGT_GR 0x45 /* BLC Gr Channel Target Value */
|
||||
#define TGT_B 0x42 /* BLC Blue Channel Target Value */
|
||||
#define TGT_R 0x43 /* BLC Red Channel Target Value */
|
||||
#define TGT_GB 0x44 /* BLC Gb Channel Target Value */
|
||||
#define TGT_GR 0x45 /* BLC Gr Channel Target Value */
|
||||
|
||||
#define LC_CTR 0x46 /* Lens Correction Control */
|
||||
#define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */
|
||||
@ -219,11 +231,11 @@
|
||||
#define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */
|
||||
#define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */
|
||||
|
||||
#define DSP_CTRL2 0x65 /* DSP Control Byte 2 */
|
||||
#define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */
|
||||
#define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */
|
||||
#define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */
|
||||
#define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */
|
||||
#define DSP_CTRL2 0x65 /* DSP Control Byte 2 */
|
||||
#define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */
|
||||
#define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */
|
||||
#define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */
|
||||
#define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */
|
||||
|
||||
#define DSP_CTRL3 0x66 /* DSP Control Byte 3 */
|
||||
#define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */
|
||||
@ -234,13 +246,11 @@
|
||||
#define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */
|
||||
#define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5))
|
||||
|
||||
|
||||
#define DSP_CTRL4 0x67 /* DSP Control Byte 4 */
|
||||
#define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */
|
||||
#define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */
|
||||
#define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */
|
||||
|
||||
|
||||
#define AWB_BIAS 0x68 /* AWB BLC Level Clip */
|
||||
#define AWB_CTRL1 0x69 /* AWB Control 1 */
|
||||
#define AWB_CTRL2 0x6A /* AWB Control 2 */
|
||||
@ -309,14 +319,14 @@
|
||||
#define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */
|
||||
#define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */
|
||||
|
||||
#define SDE 0xA6 /* Special Digital Effect Control */
|
||||
#define SDE_NEGATIVE_EN 0x40 /* Negative image enable */
|
||||
#define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */
|
||||
#define SDE_V_FIXED_EN 0x10 /* V fixed value enable */
|
||||
#define SDE_U_FIXED_EN 0x08 /* U fixed value enable */
|
||||
#define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */
|
||||
#define SDE_SATURATION_EN 0x02 /* Saturation enable */
|
||||
#define SDE_HUE_EN 0x01 /* Hue enable */
|
||||
#define SDE 0xA6 /* Special Digital Effect Control */
|
||||
#define SDE_NEGATIVE_EN 0x40 /* Negative image enable */
|
||||
#define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */
|
||||
#define SDE_V_FIXED_EN 0x10 /* V fixed value enable */
|
||||
#define SDE_U_FIXED_EN 0x08 /* U fixed value enable */
|
||||
#define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */
|
||||
#define SDE_SATURATION_EN 0x02 /* Saturation enable */
|
||||
#define SDE_HUE_EN 0x01 /* Hue enable */
|
||||
|
||||
#define USAT 0xA7 /* U Component Saturation Gain */
|
||||
#define VSAT 0xA8 /* V Component Saturation Gain */
|
||||
@ -330,6 +340,6 @@
|
||||
#define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */
|
||||
#define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */
|
||||
#define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */
|
||||
#define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2))*/
|
||||
#define SET_REG(reg, x) (##reg_DEFAULT|x)
|
||||
#define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2)) */
|
||||
|
||||
#endif //__REG_REGS_H__
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "ov9650.h"
|
||||
#include "systick.h"
|
||||
#include "ov9650_regs.h"
|
||||
#include "omv_boardconfig.h"
|
||||
|
||||
#define NUM_BR_LEVELS 7
|
||||
|
||||
@ -320,23 +321,6 @@ static int set_brightness(sensor_t *sensor, int level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//static int set_exposure(sensor_t *sensor, int exposure)
|
||||
//{
|
||||
// uint8_t val;
|
||||
// val = cambus_readb(sensor->slv_addr, REG_COM1);
|
||||
|
||||
// /* exposure [1:0] */
|
||||
// cambus_writeb(sensor->slv_addr, REG_COM1, val | (exposure&0x03));
|
||||
|
||||
// /* exposure [9:2] */
|
||||
// cambus_writeb(sensor->slv_addr, REG_AECH, ((exposure>>2)&0xFF));
|
||||
|
||||
// /* exposure [15:10] */
|
||||
// cambus_writeb(sensor->slv_addr, REG_AECHM, ((exposure>>10)&0x3F));
|
||||
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling)
|
||||
{
|
||||
/* Write gain ceiling register */
|
||||
@ -355,15 +339,73 @@ static int set_auto_gain(sensor_t *sensor, int enable, int gain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure)
|
||||
static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us)
|
||||
{
|
||||
uint8_t val;
|
||||
cambus_readb(sensor->slv_addr, REG_COM8, &val);
|
||||
uint8_t reg;
|
||||
int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_COM8, (reg & (~REG_COM8_AEC)) | ((enable != 0) & REG_COM8_AEC));
|
||||
|
||||
cambus_writeb(sensor->slv_addr, REG_COM8,
|
||||
enable ? (val | REG_COM8_AEC) : (val & ~REG_COM8_AEC));
|
||||
if ((enable == 0) && (exposure_us >= 0)) {
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_COM7, ®);
|
||||
int t_line = 0, t_pclk = (reg & REG_COM7_RGB) ? 2 : 1;
|
||||
|
||||
if (reg & REG_COM7_VGA) t_line = 640 + 160;
|
||||
if (reg & REG_COM7_CIF) t_line = 352 + 168;
|
||||
if (reg & REG_COM7_QVGA) t_line = 320 + 80;
|
||||
if (reg & REG_COM7_QCIF) t_line = 176 + 84;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_CLKRC, ®);
|
||||
int pll_mult = (reg & REG_CLKRC_DOUBLE) ? 2 : 1;
|
||||
int clk_rc = ((reg & REG_CLKRC_DIVIDER_MASK) + 1) * 2;
|
||||
|
||||
return 0;
|
||||
int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000);
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_COM1, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_COM1, (reg & 0xFC) | ((exposure >> 0) & 0x3));
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_AECH, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_AECH, (reg & 0x00) | ((exposure >> 2) & 0xFF));
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_AECHM, ®);
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_AECHM, (reg & 0xC0) | ((exposure >> 10) & 0x3F));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_exposure_us(sensor_t *sensor, int *exposure_us)
|
||||
{
|
||||
uint8_t reg, aec_10, aec_92, aec_1510;
|
||||
int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®);
|
||||
|
||||
if (reg & REG_COM8_AEC) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg & (~REG_COM8_AEC));
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_COM1, &aec_10);
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_AECH, &aec_92);
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_AECHM, &aec_1510);
|
||||
|
||||
if (reg & REG_COM8_AEC) {
|
||||
ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg | REG_COM8_AEC);
|
||||
}
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_COM7, ®);
|
||||
int t_line = 0, t_pclk = (reg & REG_COM7_RGB) ? 2 : 1;
|
||||
|
||||
if (reg & REG_COM7_VGA) t_line = 640 + 160;
|
||||
if (reg & REG_COM7_CIF) t_line = 352 + 168;
|
||||
if (reg & REG_COM7_QVGA) t_line = 320 + 80;
|
||||
if (reg & REG_COM7_QCIF) t_line = 176 + 84;
|
||||
|
||||
ret |= cambus_readb(sensor->slv_addr, REG_CLKRC, ®);
|
||||
int pll_mult = (reg & REG_CLKRC_DOUBLE) ? 2 : 1;
|
||||
int clk_rc = ((reg & REG_CLKRC_DIVIDER_MASK) + 1) * 2;
|
||||
|
||||
uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0);
|
||||
*exposure_us = (exposure*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_auto_whitebal(sensor_t *sensor, int enable, int r_gain, int g_gain, int b_gain)
|
||||
@ -411,6 +453,7 @@ int ov9650_init(sensor_t *sensor)
|
||||
sensor->set_gainceiling = set_gainceiling;
|
||||
sensor->set_auto_gain = set_auto_gain;
|
||||
sensor->set_auto_exposure = set_auto_exposure;
|
||||
sensor->get_exposure_us = get_exposure_us;
|
||||
sensor->set_auto_whitebal = set_auto_whitebal;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
|
||||
@ -5,8 +5,10 @@
|
||||
*
|
||||
* OV9650 register definitions.
|
||||
*/
|
||||
|
||||
#ifndef __REG_REGS_H__
|
||||
#define __REG_REGS_H__
|
||||
|
||||
#define REG_GAIN 0x00
|
||||
#define REG_BLUE 0x01
|
||||
#define REG_RED 0x02
|
||||
@ -110,7 +112,9 @@
|
||||
#define REG_COM26 0xA5
|
||||
#define REG_GGAIN 0xA6
|
||||
#define REG_VGAST 0xA7
|
||||
|
||||
/* register bits */
|
||||
|
||||
#define REG_COM1_QQCIF (1<<5)
|
||||
#define REG_COM1_QQVGA (1<<5)
|
||||
#define REG_COM1_SKIP2 (1<<2)
|
||||
@ -125,4 +129,7 @@
|
||||
#define REG_COM8_AEC (1<<0)
|
||||
#define REG_MVFP_HMIRROR (1<<5)
|
||||
#define REG_MVFP_VFLIP (1<<4)
|
||||
#define REG_CLKRC_DOUBLE (1<<8)
|
||||
#define REG_CLKRC_DIVIDER_MASK (0x3F)
|
||||
|
||||
#endif //__REG_REGS_H__
|
||||
|
||||
@ -354,12 +354,19 @@ static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_ma
|
||||
}
|
||||
|
||||
static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
int enable = mp_obj_get_int(args[0]);
|
||||
int value = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_value), -1);
|
||||
if (sensor_set_auto_exposure(enable, value) != 0) {
|
||||
return mp_const_false;
|
||||
int exposure_us = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_exposure_us), -1);
|
||||
if (sensor_set_auto_exposure(mp_obj_get_int(args[0]), exposure_us) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!"));
|
||||
}
|
||||
return mp_const_true;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
static mp_obj_t py_sensor_get_exposure_us() {
|
||||
int exposure_us;
|
||||
if (sensor_get_exposure_us(&exposure_us) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!"));
|
||||
}
|
||||
return mp_obj_new_int(exposure_us);
|
||||
}
|
||||
|
||||
static mp_obj_t py_sensor_set_auto_whitebal(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
@ -444,6 +451,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_quality_obj, py_sensor_se
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_colorbar_obj, py_sensor_set_colorbar);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_gain_obj, 1,py_sensor_set_auto_gain);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_exposure_obj,1,py_sensor_set_auto_exposure);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_exposure_us_obj, py_sensor_get_exposure_us);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_whitebal_obj,1,py_sensor_set_auto_whitebal);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_hmirror_obj, py_sensor_set_hmirror);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vflip_obj, py_sensor_set_vflip);
|
||||
@ -520,6 +528,7 @@ STATIC const mp_map_elem_t globals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_colorbar), (mp_obj_t)&py_sensor_set_colorbar_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_gain), (mp_obj_t)&py_sensor_set_auto_gain_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_exposure), (mp_obj_t)&py_sensor_set_auto_exposure_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_exposure_us), (mp_obj_t)&py_sensor_get_exposure_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_whitebal), (mp_obj_t)&py_sensor_set_auto_whitebal_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_hmirror), (mp_obj_t)&py_sensor_set_hmirror_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_vflip), (mp_obj_t)&py_sensor_set_vflip_obj },
|
||||
|
||||
@ -223,6 +223,8 @@ Q(set_quality)
|
||||
Q(set_colorbar)
|
||||
Q(set_auto_gain)
|
||||
Q(set_auto_exposure)
|
||||
Q(exposure_us)
|
||||
Q(get_exposure_us)
|
||||
Q(set_auto_whitebal)
|
||||
Q(set_hmirror)
|
||||
Q(set_vflip)
|
||||
|
||||
@ -536,11 +536,22 @@ int sensor_set_auto_gain(int enable, int gain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sensor_set_auto_exposure(int enable, int exposure)
|
||||
int sensor_set_auto_exposure(int enable, int exposure_us)
|
||||
{
|
||||
/* call the sensor specific function */
|
||||
if (sensor.set_auto_exposure == NULL
|
||||
|| sensor.set_auto_exposure(&sensor, enable, exposure) != 0) {
|
||||
|| sensor.set_auto_exposure(&sensor, enable, exposure_us) != 0) {
|
||||
/* operation not supported */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sensor_get_exposure_us(int *exposure_us)
|
||||
{
|
||||
/* call the sensor specific function */
|
||||
if (sensor.get_exposure_us == NULL
|
||||
|| sensor.get_exposure_us(&sensor, exposure_us) != 0) {
|
||||
/* operation not supported */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -136,7 +136,8 @@ typedef struct _sensor {
|
||||
int (*set_quality) (sensor_t *sensor, int quality);
|
||||
int (*set_colorbar) (sensor_t *sensor, int enable);
|
||||
int (*set_auto_gain) (sensor_t *sensor, int enable, int gain);
|
||||
int (*set_auto_exposure) (sensor_t *sensor, int enable, int exposure);
|
||||
int (*set_auto_exposure) (sensor_t *sensor, int enable, int exposure_us);
|
||||
int (*get_exposure_us) (sensor_t *sensor, int *exposure_us);
|
||||
int (*set_auto_whitebal) (sensor_t *sensor, int enable, int r_gain, int g_gain, int b_gain);
|
||||
int (*set_hmirror) (sensor_t *sensor, int enable);
|
||||
int (*set_vflip) (sensor_t *sensor, int enable);
|
||||
@ -203,7 +204,10 @@ int sensor_set_colorbar(int enable);
|
||||
int sensor_set_auto_gain(int enable, int gain);
|
||||
|
||||
// Enable auto exposure or set value manually.
|
||||
int sensor_set_auto_exposure(int enable, int exposure);
|
||||
int sensor_set_auto_exposure(int enable, int exposure_us);
|
||||
|
||||
// Get the exposure value.
|
||||
int sensor_get_exposure_us(int *get_exposure_us);
|
||||
|
||||
// Enable auto white balance or set value manually.
|
||||
int sensor_set_auto_whitebal(int enable, int r_gain, int g_gain, int b_gain);
|
||||
|
||||
53
usr/examples/02-Board-Control/sensor_exposure_control.py
Normal file
53
usr/examples/02-Board-Control/sensor_exposure_control.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Sensor Exposure Control
|
||||
#
|
||||
# This example shows off how to cotnrol the camera sensor's
|
||||
# exposure manually versus letting auto exposure control run.
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
# Change this value to adjust the exposure. Try 10.0/0.1/etc.
|
||||
EXPOSURE_TIME_SCALE = 1.0
|
||||
|
||||
sensor.reset() # Reset and initialize the sensor.
|
||||
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
|
||||
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
|
||||
|
||||
# Print out the initial exposure time for comparison.
|
||||
print("Initial exposure == %d" % sensor.get_exposure_us())
|
||||
|
||||
sensor.skip_frames(time = 2000) # Wait for settings take effect.
|
||||
clock = time.clock() # Create a clock object to track the FPS.
|
||||
|
||||
# You have to turn automatic gain control and automatic white blance off
|
||||
# otherwise they will change the image gains to undo any exposure settings
|
||||
# that you put in place...
|
||||
sensor.set_auto_gain(False)
|
||||
sensor.set_auto_whitebal(False)
|
||||
|
||||
current_exposure_time_in_microseconds = sensor.get_exposure_us()
|
||||
print("Current Exposure == %d" % current_exposure_time_in_microseconds)
|
||||
|
||||
# Auto exposure control (AEC) is enabled by default. Calling the below function
|
||||
# disables sensor auto exposure control. The additionally "exposure_us"
|
||||
# argument then overrides the auto exposure value after AEC is disabled.
|
||||
sensor.set_auto_exposure(False, \
|
||||
exposure_us = int(current_exposure_time_in_microseconds * EXPOSURE_TIME_SCALE))
|
||||
|
||||
print("New exposure == %d" % sensor.get_exposure_us())
|
||||
# sensor.get_exposure_us() returns the exact camera sensor exposure time
|
||||
# in microseconds. However, this may be a different number than what was
|
||||
# commanded because the sensor code converts the exposure time in microseconds
|
||||
# to a row/pixel/clock time which doesn't perfectly match with microseconds...
|
||||
|
||||
# If you want to turn auto exposure back on do: sensor.set_auto_exposure(True)
|
||||
# Note that the camera sensor will then change the exposure time as it likes.
|
||||
|
||||
# Doing: sensor.set_auto_exposure(False)
|
||||
# Just disables the exposure value update but does not change the exposure
|
||||
# value the camera sensor determined was good.
|
||||
|
||||
while(True):
|
||||
clock.tick() # Update the FPS clock.
|
||||
img = sensor.snapshot() # Take a picture and return the image.
|
||||
print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected
|
||||
# to the IDE. The FPS should increase once disconnected.
|
||||
Loading…
Reference in New Issue
Block a user