Add auto gain control ceiling value to be settable by the auto gain

method.

Things are in dB now too. Need to remove the previous settable method.
This commit is contained in:
Kwabena W. Agyeman 2017-12-30 23:54:19 -05:00
parent aeb0238040
commit 139cdbdbc9
10 changed files with 86 additions and 13 deletions

View File

@ -101,6 +101,7 @@
#define MT9V034_VERTICAL_BLANKING_A (0x06) #define MT9V034_VERTICAL_BLANKING_A (0x06)
#define MT9V034_COARSE_SHUTTER_WIDTH_TOTAL_A (0x0B) #define MT9V034_COARSE_SHUTTER_WIDTH_TOTAL_A (0x0B)
#define MT9V034_ANALOG_GAIN_CONTROL (0x35) #define MT9V034_ANALOG_GAIN_CONTROL (0x35)
#define MT9V034_MAX_GAIN (0xAB)
#define MT9V034_FINE_SHUTTER_WIDTH_TOTAL_A (0xD5) #define MT9V034_FINE_SHUTTER_WIDTH_TOTAL_A (0xD5)
static int reset(sensor_t *sensor) static int reset(sensor_t *sensor)
@ -202,17 +203,22 @@ static int set_colorbar(sensor_t *sensor, int enable)
return 0; return 0;
} }
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db) static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{ {
uint16_t reg, agc_gain; uint16_t reg;
int ret = cambus_readw(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, &reg); int ret = cambus_readw(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, &reg);
ret |= cambus_writew(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, (reg & (~MT9V034_AGC_ENABLE)) | ((enable != 0) ? MT9V034_AGC_ENABLE : 0)); ret |= cambus_writew(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, (reg & (~MT9V034_AGC_ENABLE)) | ((enable != 0) ? MT9V034_AGC_ENABLE : 0));
if ((enable == 0) && (gain_db >= 0)) { if ((enable == 0) && (gain_db >= 0)) {
int gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db / 20.0) * fast_log(10.0)) * 16.0), 127), 0); int gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db / 20.0) * fast_log(10.0)) * 16.0), 127), 0);
ret |= cambus_readw(sensor->slv_addr, MT9V034_ANALOG_GAIN_CONTROL, &agc_gain); ret |= cambus_readw(sensor->slv_addr, MT9V034_ANALOG_GAIN_CONTROL, &reg);
ret |= cambus_writew(sensor->slv_addr, MT9V034_ANALOG_GAIN_CONTROL, (agc_gain & 0xFF80) | gain); ret |= cambus_writew(sensor->slv_addr, MT9V034_ANALOG_GAIN_CONTROL, (reg & 0xFF80) | gain);
} else if ((enable != 0) && (gain_db_ceiling >= 0)) {
int gain_ceiling = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)) * 16.0), 127), 16);
ret |= cambus_readw(sensor->slv_addr, MT9V034_MAX_GAIN, &reg);
ret |= cambus_writew(sensor->slv_addr, MT9V034_MAX_GAIN, (reg & 0xFF80) | gain_ceiling);
} }
return ret; return ret;

View File

@ -602,7 +602,7 @@ static int set_colorbar(sensor_t *sensor, int enable)
return cambus_writeb(sensor->slv_addr, COM7, reg) | ret; return cambus_writeb(sensor->slv_addr, COM7, reg) | ret;
} }
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db) static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{ {
uint8_t reg; uint8_t reg;
int ret = cambus_readb(sensor->slv_addr, BANK_SEL, &reg); int ret = cambus_readb(sensor->slv_addr, BANK_SEL, &reg);
@ -624,6 +624,11 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db)
} }
ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0)); ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
} else if ((enable != 0) && (gain_db_ceiling >= 0)) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 1.0);
ret |= cambus_readb(sensor->slv_addr, COM9, &reg);
ret |= cambus_writeb(sensor->slv_addr, COM9, (reg & 0x1F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 5));
} }
return ret; return ret;

View File

@ -352,7 +352,7 @@ static int set_colorbar(sensor_t *sensor, int enable)
return cambus_writeb(sensor->slv_addr, DSP_CTRL3, reg) | ret; return cambus_writeb(sensor->slv_addr, DSP_CTRL3, reg) | ret;
} }
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db) static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{ {
uint8_t reg; uint8_t reg;
int ret = cambus_readb(sensor->slv_addr, COM8, &reg); int ret = cambus_readb(sensor->slv_addr, COM8, &reg);
@ -372,6 +372,11 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db)
} }
ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0)); ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
} else if ((enable != 0) && (gain_db_ceiling >= 0)) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 32.0), 1.0);
ret |= cambus_readb(sensor->slv_addr, COM9, &reg);
ret |= cambus_writeb(sensor->slv_addr, COM9, (reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4));
} }
return ret; return ret;

View File

@ -328,7 +328,7 @@ static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling)
return 0; return 0;
} }
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db) static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{ {
uint8_t reg; uint8_t reg;
int ret = cambus_readb(sensor->slv_addr, REG_COM8, &reg); int ret = cambus_readb(sensor->slv_addr, REG_COM8, &reg);
@ -350,6 +350,11 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db)
ret |= cambus_writeb(sensor->slv_addr, REG_GAIN, ((gain_hi & 0x0F) << 4) | (gain_lo << 0)); ret |= cambus_writeb(sensor->slv_addr, REG_GAIN, ((gain_hi & 0x0F) << 4) | (gain_lo << 0));
ret |= cambus_readb(sensor->slv_addr, REG_VREF, &reg); ret |= cambus_readb(sensor->slv_addr, REG_VREF, &reg);
ret |= cambus_writeb(sensor->slv_addr, REG_VREF, ((gain_hi & 0x30) << 2) | (reg & 0x3F)); ret |= cambus_writeb(sensor->slv_addr, REG_VREF, ((gain_hi & 0x30) << 2) | (reg & 0x3F));
} else if ((enable != 0) && (gain_db_ceiling >= 0)) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 1.0);
ret |= cambus_readb(sensor->slv_addr, REG_COM9, &reg);
ret |= cambus_writeb(sensor->slv_addr, REG_COM9, (reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4));
} }
return ret; return ret;

View File

@ -345,8 +345,10 @@ static mp_obj_t py_sensor_set_colorbar(mp_obj_t enable) {
} }
static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
int enable = mp_obj_get_int(args[0]);
float gain_db = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), -1); float gain_db = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), -1);
if (sensor_set_auto_gain(mp_obj_get_int(args[0]), gain_db) != 0) { float gain_db_ceiling = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db_ceiling), -1);
if (sensor_set_auto_gain(enable, gain_db, gain_db_ceiling) != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!"));
} }
return mp_const_none; return mp_const_none;

View File

@ -223,6 +223,7 @@ Q(set_quality)
Q(set_colorbar) Q(set_colorbar)
Q(set_auto_gain) Q(set_auto_gain)
Q(gain_db) Q(gain_db)
Q(gain_db_ceiling)
Q(get_gain_db) Q(get_gain_db)
Q(set_auto_exposure) Q(set_auto_exposure)
Q(exposure_us) Q(exposure_us)

View File

@ -525,11 +525,11 @@ int sensor_set_colorbar(int enable)
return 0; return 0;
} }
int sensor_set_auto_gain(int enable, float gain_db) int sensor_set_auto_gain(int enable, float gain_db, float gain_db_ceiling)
{ {
/* call the sensor specific function */ /* call the sensor specific function */
if (sensor.set_auto_gain == NULL if (sensor.set_auto_gain == NULL
|| sensor.set_auto_gain(&sensor, enable, gain_db) != 0) { || sensor.set_auto_gain(&sensor, enable, gain_db, gain_db_ceiling) != 0) {
/* operation not supported */ /* operation not supported */
return -1; return -1;
} }

View File

@ -135,7 +135,7 @@ typedef struct _sensor {
int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling); int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
int (*set_quality) (sensor_t *sensor, int quality); int (*set_quality) (sensor_t *sensor, int quality);
int (*set_colorbar) (sensor_t *sensor, int enable); int (*set_colorbar) (sensor_t *sensor, int enable);
int (*set_auto_gain) (sensor_t *sensor, int enable, float gain_db); int (*set_auto_gain) (sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling);
int (*get_gain_db) (sensor_t *sensor, float *gain_db); int (*get_gain_db) (sensor_t *sensor, float *gain_db);
int (*set_auto_exposure) (sensor_t *sensor, int enable, int exposure_us); int (*set_auto_exposure) (sensor_t *sensor, int enable, int exposure_us);
int (*get_exposure_us) (sensor_t *sensor, int *exposure_us); int (*get_exposure_us) (sensor_t *sensor, int *exposure_us);
@ -202,7 +202,7 @@ int sensor_set_quality(int qs);
int sensor_set_colorbar(int enable); int sensor_set_colorbar(int enable);
// Enable auto gain or set value manually. // Enable auto gain or set value manually.
int sensor_set_auto_gain(int enable, float gain_db); int sensor_set_auto_gain(int enable, float gain_db, float gain_db_ceiling);
// Get the gain value. // Get the gain value.
int sensor_get_gain_db(float *gain_db); int sensor_get_gain_db(float *gain_db);

View File

@ -0,0 +1,49 @@
# Sensor Auto Gain Control
#
# This example shows off how to control the sensor's gain
# using the automatic gain control algorithm.
# What's the difference between gain and exposure control?
#
# Well, by increasing the exposure time for the image you're getting more
# light on the camera. This gives you the best signal to noise ratio. You
# in general always want to increase the expsoure time... except, when you
# increase the exposure time you decrease the maximum possible frame rate
# and if anything moves in the image it will start to blur more with a
# higher exposure time. Gain control allows you to increase the output per
# pixel using analog and digital multipliers... however, it also amplifies
# noise. So, it's best to let the exposure increase as much as possible
# and then use gain control to make up any remaining ground.
# We can achieve the above by setting a gain ceiling on the automatic
# gain control algorithm. Once this is set the algorithm will have to
# increase the exposure time to meet any gain needs versus using gain
# to do so. However, this comes at the price of the exposure time varying
# more when the lighting changes versus the exposure being constant and
# the gain changing.
import sensor, image, time
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)
# The gain db ceiling maxes out at about 24 db for the OV7725 sensor.
sensor.set_auto_gain(True, gain_db_ceiling = 16.0) # Default gain.
# Note! If you set the gain ceiling to low without adjusting the exposure control
# target value then you'll just get a lot of oscillation from the exposure
# control if it's on.
sensor.skip_frames(time = 2000) # Wait for settings take effect.
clock = time.clock() # Create a clock object to track the FPS.
# Note! You can't read the gain/exposure values in the loop while AGC/AEC is on
# since we have to disable the sensor auto control in order to read the values
# (they are spread accross registers and can't be read atomically if the control is on).
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.

View File

@ -1,4 +1,4 @@
# Sensor Gain Control # Sensor Manual Gain Control
# #
# This example shows off how to control the camera sensor's # This example shows off how to control the camera sensor's
# gain manually versus letting auto gain control run. # gain manually versus letting auto gain control run.