Merge pull request #1938 from kwagyeman/kwabena/sensor_full_control

sensors: Add full control.
This commit is contained in:
Ibrahim Abdelkader 2023-10-04 20:26:09 +03:00 committed by GitHub
commit 9b5b2476c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 445 additions and 85 deletions

View File

@ -0,0 +1,81 @@
# Sensor Save and Restore Settings
#
# This example shows off how to save and then restore camera settings
# after a sensor reset and/or powerdown.
import sensor
import time
# Set pixel format to RGB565 (or GRAYSCALE)
target_pixformat = sensor.RGB565
# Set frame size to QVGA (320x240)
target_framesize = sensor.QVGA
sensor.reset()
sensor.set_pixformat(target_pixformat)
sensor.set_framesize(target_framesize)
# Delay 3 seconds to let the camera auto functions run and measure the fps.
t = time.ticks_ms()
clock = time.clock()
fps = 0
while time.ticks_diff(time.ticks_ms(), t) < 3000:
clock.tick()
sensor.snapshot()
fps = clock.fps()
# The sensor should have time now to warm up and adjust to the current environment.
# Grab the settings now before turning off the sensor.
gain = sensor.get_gain_db()
exposure = sensor.get_exposure_us()
rgb_gain = sensor.get_rgb_gain_db()
print("Gain == %f db" % gain)
print("Exposure == %d us" % exposure)
print("RGB Gain == %f db, %f db, %f db" % (rgb_gain[0], rgb_gain[1], rgb_gain[2]))
print("Powering Off Sensor")
sensor.shutdown(True)
time.sleep(2)
# Disable all settling time delays in the sensor driver code. Turning this off WILL result in
# corrupted images appearing when modifying settings. However, now you can change sensor settings
# in bulk quickly.
sensor.disable_delays(True)
ts = time.ticks_ms()
print("Powering On Sensor")
sensor.shutdown(False)
sensor.reset()
sensor.set_pixformat(target_pixformat)
sensor.set_framesize(target_framesize)
sensor.set_auto_gain(False, gain_db=gain)
sensor.set_auto_exposure(False, exposure_us=exposure)
sensor.set_auto_whitebal(False, rgb_gain_db=rgb_gain)
# You need to delay before calling snapshot as the image coming out of the camera right now is
# most likely to be very corrupt. The exact amount of time to delay below is application
# dependent. However, you should probably wait for a frame.
time.sleep(1.0 / fps)
print("Restore Delay %d ms" % (time.ticks_ms() - ts))
gain = sensor.get_gain_db()
exposure = sensor.get_exposure_us()
rgb_gain = sensor.get_rgb_gain_db()
print("Gain == %f db" % gain)
print("Exposure == %d us" % exposure)
print("RGB Gain == %f db, %f db, %f db" % (rgb_gain[0], rgb_gain[1], rgb_gain[2]))
clock = time.clock()
# Image should look like it did before save and restore.
while True:
clock.tick()
img = sensor.snapshot()
# print(clock.fps())

View File

@ -141,6 +141,8 @@ typedef enum {
IOCTL_PAUSE_AUTO_FOCUS,
IOCTL_RESET_AUTO_FOCUS,
IOCTL_WAIT_ON_AUTO_FOCUS,
IOCTL_SET_NIGHT_MODE,
IOCTL_GET_NIGHT_MODE,
IOCTL_LEPTON_GET_WIDTH,
IOCTL_LEPTON_GET_HEIGHT,
IOCTL_LEPTON_GET_RADIOMETRY,
@ -219,9 +221,11 @@ typedef struct _sensor {
uint32_t yuv_swap : 1; // Byte-swap 2BPP YUV formats after capture.
uint32_t bayer : 3; // Bayer/CFA pattern.
uint32_t yuv_order : 1; // YUV/YVU order.
uint32_t blc_size : 4; // Number of black level calibration registers.
} hw_flags;
const uint16_t *color_palette; // Color palette used for color lookup.
bool disable_delays; // Set to true to disable all sensor settling time delays.
bool disable_full_flush; // Turn off default frame buffer flush policy when full.
vsync_cb_t vsync_callback; // VSYNC callback.
@ -265,6 +269,8 @@ typedef struct _sensor {
int (*get_exposure_us) (sensor_t *sensor, int *exposure_us);
int (*set_auto_whitebal) (sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db);
int (*get_rgb_gain_db) (sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db);
int (*set_auto_blc) (sensor_t *sensor, int enable, int *regs);
int (*get_blc_regs) (sensor_t *sensor, int *regs);
int (*set_hmirror) (sensor_t *sensor, int enable);
int (*set_vflip) (sensor_t *sensor, int enable);
int (*set_special_effect) (sensor_t *sensor, sde_t sde);
@ -378,6 +384,12 @@ int sensor_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float
// Get the rgb gain values.
int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db);
// Enable auto blc (black level calibration) or set from previous calibration.
int sensor_set_auto_blc(int enable, int *regs);
// Get black level valibration register values.
int sensor_get_blc_regs(int *regs);
// Enable/disable the hmirror mode.
int sensor_set_hmirror(int enable);

View File

@ -583,7 +583,9 @@ __weak int sensor_set_pixformat(pixformat_t pixformat) {
return SENSOR_ERROR_CTL_FAILED;
}
mp_hal_delay_ms(100); // wait for the camera to settle
if (!sensor.disable_delays) {
mp_hal_delay_ms(100); // wait for the camera to settle
}
// Set pixel format
sensor.pixformat = pixformat;
@ -619,7 +621,9 @@ __weak int sensor_set_framesize(framesize_t framesize) {
return SENSOR_ERROR_CTL_FAILED;
}
mp_hal_delay_ms(100); // wait for the camera to settle
if (!sensor.disable_delays) {
mp_hal_delay_ms(100); // wait for the camera to settle
}
// Set framebuffer size
sensor.framesize = framesize;
@ -906,6 +910,34 @@ __weak int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_g
return 0;
}
__weak int sensor_set_auto_blc(int enable, int *regs) {
// Check if the control is supported.
if (sensor.set_auto_blc == NULL) {
return SENSOR_ERROR_CTL_UNSUPPORTED;
}
// Call the sensor specific function.
if (sensor.set_auto_blc(&sensor, enable, regs) != 0) {
return SENSOR_ERROR_CTL_FAILED;
}
return 0;
}
__weak int sensor_get_blc_regs(int *regs) {
// Check if the control is supported.
if (sensor.get_blc_regs == NULL) {
return SENSOR_ERROR_CTL_UNSUPPORTED;
}
// Call the sensor specific function.
if (sensor.get_blc_regs(&sensor, regs) != 0) {
return SENSOR_ERROR_CTL_FAILED;
}
return 0;
}
__weak int sensor_set_hmirror(int enable) {
// Check if the value has changed.
if (sensor.hmirror == ((bool) enable)) {
@ -929,7 +961,9 @@ __weak int sensor_set_hmirror(int enable) {
sensor.hmirror = enable;
// Wait for the camera to settle
mp_hal_delay_ms(100);
if (!sensor.disable_delays) {
mp_hal_delay_ms(100);
}
return 0;
}
@ -961,7 +995,9 @@ __weak int sensor_set_vflip(int enable) {
sensor.vflip = enable;
// Wait for the camera to settle
mp_hal_delay_ms(100);
if (!sensor.disable_delays) {
mp_hal_delay_ms(100);
}
return 0;
}

View File

@ -451,6 +451,48 @@ static mp_obj_t py_sensor_get_rgb_gain_db() {
});
}
static mp_obj_t py_sensor_set_auto_blc(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_enable, ARG_regs };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_enable, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_regs, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int enable = args[ARG_enable].u_int;
int regs[sensor.hw_flags.blc_size];
bool regs_present = args[ARG_regs].u_obj != mp_const_none;
if (regs_present) {
mp_obj_t *arg_array;
mp_obj_get_array_fixed_n(args[ARG_regs].u_obj, sensor.hw_flags.blc_size, &arg_array);
for (uint32_t i = 0; i < sensor.hw_flags.blc_size; i++) {
regs[i] = mp_obj_get_int(arg_array[i]);
}
}
int error = sensor_set_auto_blc(enable, regs_present ? regs : NULL);
if (error != 0) {
sensor_raise_error(error);
}
return mp_const_none;
}
static mp_obj_t py_sensor_get_blc_regs() {
int regs[sensor.hw_flags.blc_size];
int error = sensor_get_blc_regs(regs);
if (error != 0) {
sensor_raise_error(error);
}
mp_obj_list_t *l = mp_obj_new_list(sensor.hw_flags.blc_size, NULL);
for (uint32_t i = 0; i < sensor.hw_flags.blc_size; i++) {
l->items[i] = mp_obj_new_int(regs[i]);
}
return l;
}
static mp_obj_t py_sensor_set_hmirror(mp_obj_t enable) {
int error = sensor_set_hmirror(mp_obj_is_true(enable));
if (error != 0) {
@ -522,6 +564,15 @@ static mp_obj_t py_sensor_get_framebuffers() {
return mp_obj_new_int(framebuffer->n_buffers);
}
static mp_obj_t py_sensor_disable_delays(uint n_args, const mp_obj_t *args) {
if (!n_args) {
return mp_obj_new_bool(sensor.disable_delays);
}
sensor.disable_delays = mp_obj_get_int(args[0]);
return mp_const_none;
}
static mp_obj_t py_sensor_disable_full_flush(uint n_args, const mp_obj_t *args) {
if (!n_args) {
return mp_obj_new_bool(sensor.disable_full_flush);
@ -656,6 +707,22 @@ static mp_obj_t py_sensor_ioctl(uint n_args, const mp_obj_t *args) {
}
#endif
case IOCTL_SET_NIGHT_MODE: {
if (n_args >= 2) {
error = sensor_ioctl(request, mp_obj_get_int(args[1]));
}
break;
}
case IOCTL_GET_NIGHT_MODE: {
int enabled;
error = sensor_ioctl(request, &enabled);
if (error == 0) {
ret_obj = mp_obj_new_bool(enabled);
}
break;
}
case IOCTL_LEPTON_GET_WIDTH: {
int width;
error = sensor_ioctl(request, &width);
@ -915,6 +982,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_exposure_obj, 1, py_sensor_
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_0(py_sensor_get_rgb_gain_db_obj, py_sensor_get_rgb_gain_db);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_blc_obj, 1, py_sensor_set_auto_blc);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_blc_regs_obj, py_sensor_get_blc_regs);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_hmirror_obj, py_sensor_set_hmirror);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_hmirror_obj, py_sensor_get_hmirror);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vflip_obj, py_sensor_set_vflip);
@ -925,6 +994,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_auto_rotation_obj, py_sensor_se
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_auto_rotation_obj, py_sensor_get_auto_rotation);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_framebuffers_obj, py_sensor_set_framebuffers);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_framebuffers_obj, py_sensor_get_framebuffers);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_sensor_disable_delays_obj, 0, 1, py_sensor_disable_delays);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_sensor_disable_full_flush_obj, 0, 1, py_sensor_disable_full_flush);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_special_effect_obj, py_sensor_set_special_effect);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_sensor_set_lens_correction_obj, py_sensor_set_lens_correction);
@ -1028,6 +1098,8 @@ STATIC const mp_map_elem_t globals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_RESET_AUTO_FOCUS), MP_OBJ_NEW_SMALL_INT(IOCTL_RESET_AUTO_FOCUS)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_WAIT_ON_AUTO_FOCUS), MP_OBJ_NEW_SMALL_INT(IOCTL_WAIT_ON_AUTO_FOCUS)},
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_SET_NIGHT_MODE), MP_OBJ_NEW_SMALL_INT(IOCTL_SET_NIGHT_MODE)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_GET_NIGHT_MODE), MP_OBJ_NEW_SMALL_INT(IOCTL_GET_NIGHT_MODE)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_LEPTON_GET_WIDTH), MP_OBJ_NEW_SMALL_INT(IOCTL_LEPTON_GET_WIDTH)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_LEPTON_GET_HEIGHT), MP_OBJ_NEW_SMALL_INT(IOCTL_LEPTON_GET_HEIGHT)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_IOCTL_LEPTON_GET_RADIOMETRY), MP_OBJ_NEW_SMALL_INT(IOCTL_LEPTON_GET_RADIOMETRY)},
@ -1091,6 +1163,8 @@ STATIC const mp_map_elem_t globals_dict_table[] = {
{ 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_get_rgb_gain_db), (mp_obj_t) &py_sensor_get_rgb_gain_db_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_blc), (mp_obj_t) &py_sensor_set_auto_blc_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_blc_regs), (mp_obj_t) &py_sensor_get_blc_regs_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_hmirror), (mp_obj_t) &py_sensor_set_hmirror_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_hmirror), (mp_obj_t) &py_sensor_get_hmirror_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_vflip), (mp_obj_t) &py_sensor_set_vflip_obj },
@ -1101,6 +1175,7 @@ STATIC const mp_map_elem_t globals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_auto_rotation), (mp_obj_t) &py_sensor_get_auto_rotation_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_framebuffers), (mp_obj_t) &py_sensor_set_framebuffers_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_framebuffers), (mp_obj_t) &py_sensor_get_framebuffers_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_delays), (mp_obj_t) &py_sensor_disable_delays_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_full_flush), (mp_obj_t) &py_sensor_disable_full_flush_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_special_effect), (mp_obj_t) &py_sensor_set_special_effect_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_lens_correction), (mp_obj_t) &py_sensor_set_lens_correction_obj },

View File

@ -55,6 +55,8 @@ void sensor_init0() {
omv_i2c_init(&sensor.i2c_bus, sensor.i2c_bus.id, sensor.i2c_bus.speed);
}
sensor.disable_delays = false;
// Disable VSYNC IRQ and callback
sensor_set_vsync_callback(NULL);

View File

@ -521,6 +521,7 @@ endif
ifeq ($(OMV_ENABLE_UVC), 1)
UVC = uvc
# UVC object files
UVC_OBJ += $(BUILD)/$(MICROPY_DIR)/lib/libm/math.o
UVC_OBJ += $(wildcard $(BUILD)/$(UVC_DIR)/src/*.o)
UVC_OBJ += $(wildcard $(BUILD)/$(HAL_DIR)/src/*.o)
UVC_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/,\

View File

@ -102,6 +102,8 @@ void sensor_init0() {
omv_i2c_init(&sensor.i2c_bus, sensor.i2c_bus.id, sensor.i2c_bus.speed);
}
sensor.disable_delays = false;
// Disable VSYNC IRQ and callback
sensor_set_vsync_callback(NULL);

View File

@ -342,13 +342,13 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
int ret = 0;
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
gain_db = IM_MAX(IM_MIN(gain_db, 24.0f), 0.0f);
int gain = fast_ceilf(fast_log2(fast_expf((gain_db / 20.0f) * fast_log(10.0f))));
int gain = fast_ceilf(logf(expf((gain_db / 20.0f) * M_LN10)) / M_LN2);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AE_CTRL, 0); // Must disable AE
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, ANALOG_GAIN, ((gain & 0x7) << 4));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, GRP_PARAM_HOLD, 0x01);
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
gain_db_ceiling = IM_MAX(IM_MIN(gain_db_ceiling, 24.0f), 0.0f);
int gain = fast_ceilf(fast_log2(fast_expf((gain_db_ceiling / 20.0f) * fast_log(10.0f))));
int gain = fast_ceilf(logf(expf((gain_db_ceiling / 20.0f) * M_LN10) / M_LN2));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, MAX_AGAIN_FULL, (gain & 0x7));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, MAX_AGAIN_BIN2, (gain & 0x7));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AE_CTRL, 1);
@ -361,7 +361,7 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
if (omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, ANALOG_GAIN, &gain) != 0) {
return -1;
}
*gain_db = fast_floorf(fast_log(1 << (gain >> 4)) / fast_log(10.0f) * 20.0f);
*gain_db = fast_floorf(log10f(1 << (gain >> 4)) * 20.0f);
return 0;
}

View File

@ -537,12 +537,12 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
int ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AE_CTRL, &ae_ctrl);
if (!enable && (!isnanf(gain_db)) && (!isinff(gain_db))) {
gain_db = IM_MAX(IM_MIN(gain_db, 24.0f), 0.0f);
uint8_t gain = fast_ceilf(fast_log2(fast_expf((gain_db / 20.0f) * fast_log(10.0f))));
uint8_t gain = fast_ceilf(logf(expf((gain_db / 20.0f) * M_LN10)) / M_LN2);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AE_CTRL, (ae_ctrl & 0xFE));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, ANALOG_GAIN, ((gain & 0x7) << 4));
} else if (enable && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
gain_db_ceiling = IM_MAX(IM_MIN(gain_db_ceiling, 24.0f), 0.0f);
uint8_t gain = fast_ceilf(fast_log2(fast_expf((gain_db_ceiling / 20.0f) * fast_log(10.0f))));
uint8_t gain = fast_ceilf(logf(expf((gain_db_ceiling / 20.0f) * M_LN10)) / M_LN2);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, MAX_AGAIN, (gain & 0x07));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AE_CTRL, (ae_ctrl | 0x01));
}
@ -555,7 +555,7 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
if (omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, ANALOG_GAIN, &gain) != 0) {
return -1;
}
*gain_db = fast_floorf(fast_log(1 << (gain >> 4)) / fast_log(10.0f) * 20.0f);
*gain_db = fast_floorf(log10f(1 << (gain >> 4)) * 20.0f);
return 0;
}

View File

@ -785,7 +785,7 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
}
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
int gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.f) * fast_log(10.f)) * 32.f, 0xffff), 0x0000);
int gain = IM_MAX(IM_MIN(expf((gain_db / 20.0f) * M_LN10) * 32.0f, 0xffff), 0x0000);
if (omv_i2c_writew2(&sensor->i2c_bus, sensor->slv_addr, MT9M114_REG_UVC_GAIN_CONTROL, gain) != 0) {
return -1;
@ -802,7 +802,7 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
return -1;
}
*gain_db = 20.f * (fast_log(gain / 32.f) / fast_log(10.f));
*gain_db = 20.0f * log10f(gain / 32.0f);
return 0;
}

View File

@ -247,7 +247,9 @@ static int set_colorbar(sensor_t *sensor, int enable) {
ret = omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_ROW_NOISE_CORR_CONTROL, &reg);
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_ROW_NOISE_CORR_CONTROL,
(reg & (~mask)) | ((enable == 0) ? mask : 0));
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
return ret;
}
@ -259,10 +261,12 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
int ret = omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_AEC_AGC_ENABLE, &reg);
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_AEC_AGC_ENABLE,
(reg & (~agc_mask)) | ((enable != 0) ? agc_mask : 0));
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
int gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db / 20.0f) * fast_log(10.0f)) * 16.0f), 64), 16);
int gain = IM_MAX(IM_MIN(fast_roundf(expf((gain_db / 20.0f) * M_LN10) * 16.0f), 64), 16);
ret |= omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_ANALOG_GAIN, &reg);
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_ANALOG_GAIN, (reg & 0xFF80) | gain);
@ -272,7 +276,7 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0X4_ANALOG_GAIN_B, (reg & 0xFF80) | gain);
}
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
int gain_ceiling = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db_ceiling / 20.0f) * fast_log(10.0f)) * 16.0f), 64), 16);
int gain_ceiling = IM_MAX(IM_MIN(fast_roundf(expf((gain_db_ceiling / 20.0f) * M_LN10) * 16.0f), 64), 16);
int max_gain = (is_mt9v0x4(sensor)) ? MT9V0X4_MAX_GAIN : MT9V0X2_MAX_GAIN;
ret |= omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, max_gain, &reg);
@ -295,7 +299,7 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
ret |= omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, analog_gain, &gain);
}
*gain_db = 20.0 * (fast_log((gain & 0x7F) / 16.0f) / fast_log(10.0f));
*gain_db = 20.0f * log10f((gain & 0x7F) / 16.0f);
return ret;
}
@ -309,8 +313,9 @@ static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) {
ret |= omv_i2c_readw(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_AEC_AGC_ENABLE, &reg);
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_AEC_AGC_ENABLE,
(reg & (~aec_mask)) | ((enable != 0) ? aec_mask : 0));
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
int read_mode = context ? MT9V0X4_READ_MODE_B : MT9V0XX_READ_MODE;
int window_width = context ? MT9V0X4_WINDOW_WIDTH_B : MT9V0XX_WINDOW_WIDTH;
int horizontal_blanking = context ? MT9V0X4_HORIZONTAL_BLANKING_B : MT9V0XX_HORIZONTAL_BLANKING;
@ -389,7 +394,9 @@ static int set_hmirror(sensor_t *sensor, int enable) {
(read_mode & (~MT9V0XX_READ_MODE_COL_FLIP)) | ((enable == 0) ? MT9V0XX_READ_MODE_COL_FLIP : 0));
}
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
return ret;
}
@ -405,7 +412,9 @@ static int set_vflip(sensor_t *sensor, int enable) {
(read_mode & (~MT9V0XX_READ_MODE_ROW_FLIP)) | ((enable == 0) ? MT9V0XX_READ_MODE_ROW_FLIP : 0));
}
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
return ret;
}
@ -462,7 +471,9 @@ static int ioctl(sensor_t *sensor, int request, va_list ap) {
ret |= omv_i2c_writew(&sensor->i2c_bus, sensor->slv_addr, MT9V0XX_CHIP_CONTROL,
(chip_control & (~MT9V0XX_CHIP_CONTROL_MODE_MASK))
| ((enable != 0) ? MT9V0XX_CHIP_CONTROL_SNAP_MODE : MT9V0XX_CHIP_CONTROL_MASTER_MODE));
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
if (!sensor->disable_delays) {
ret |= sensor->snapshot(sensor, NULL, 0); // Force shadow mode register to update...
}
break;
}
case IOCTL_GET_TRIGGERED_MODE: {

View File

@ -359,7 +359,9 @@ static int reset(sensor_t *sensor) {
}
// Delay 300 ms
mp_hal_delay_ms(300);
if (!sensor->disable_delays) {
mp_hal_delay_ms(300);
}
return ret;
}
@ -584,20 +586,20 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM8, (reg & (~COM8_AGC_EN)) | ((enable != 0) ? COM8_AGC_EN : 0));
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 32.0), 1.0);
float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0f) * M_LN10), 32.0f), 1.0f);
int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
int gain_temp = fast_ceilf(logf(IM_MAX(gain / 2.0f, 1.0f)) / M_LN2);
int gain_hi = 0xF >> (4 - gain_temp);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0f) * 16.0f), 15);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 2.0);
float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0f) * M_LN10), 128.0f), 2.0f);
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, COM9, &reg);
ret |=
omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM9,
(reg & 0x1F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 5));
(reg & 0x1F) | ((fast_ceilf(logf(gain_ceiling) / M_LN2) - 1) << 5));
}
return ret;
@ -623,8 +625,8 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
// DISABLED
int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
*gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0));
float lo_gain = 1.0f + (((gain >> 0) & 0xF) / 16.0f);
*gain_db = 20.0f * log10f(hi_gain * lo_gain);
return ret;
}

View File

@ -705,7 +705,9 @@ static int reset(sensor_t *sensor) {
#endif
// Delay 300 ms
mp_hal_delay_ms(300);
if (!sensor->disable_delays) {
mp_hal_delay_ms(300);
}
return ret;
}
@ -1077,13 +1079,13 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_MANUAL, (reg & 0xFD) | ((enable == 0) << 1));
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
int gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)) * 16.0, 1023), 0);
int gain = IM_MAX(IM_MIN(fast_roundf(expf((gain_db / 20.0f) * M_LN10) * 16.0f), 1023), 0);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_REAL_GAIN_H, &reg);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_REAL_GAIN_H, (reg & 0xFC) | (gain >> 8));
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_REAL_GAIN_L, gain);
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
int gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)) * 16.0, 1023), 0);
int gain_ceiling = IM_MAX(IM_MIN(fast_roundf(expf((gain_db_ceiling / 20.0f) * M_LN10) * 16.0f), 1023), 0);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_GAIN_CEILING_H, &reg);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AEC_GAIN_CEILING_H, (reg & 0xFC) | (gain_ceiling >> 8));
@ -1099,7 +1101,7 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
int ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_REAL_GAIN_H, &gainh);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_PK_REAL_GAIN_L, &gainl);
*gain_db = 20.0 * (fast_log((((gainh & 0x3) << 8) | gainl) / 16.0) / fast_log(10.0));
*gain_db = 20.0f * log10f((((gainh & 0x3) << 8) | gainl) / 16.0f);
return ret;
}
@ -1173,7 +1175,7 @@ static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) {
}
static int get_exposure_us(sensor_t *sensor, int *exposure_us) {
uint8_t spc0, spc1, spc2, spc3, sysrootdiv, aec_0, aec_1, aec_2, hts_h, hts_l;
uint8_t spc0, spc1, spc2, spc3, sysrootdiv, aec_0, aec_1, aec_2, hts_h, hts_l, vts_h, vts_l;
int ret = 0;
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, SC_PLL_CONTRL0, &spc0);
@ -1189,8 +1191,14 @@ static int get_exposure_us(sensor_t *sensor, int *exposure_us) {
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, TIMING_HTS_H, &hts_h);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, TIMING_HTS_L, &hts_l);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, TIMING_VTS_H, &vts_h);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, TIMING_VTS_L, &vts_l);
uint32_t aec = ((aec_0 << 16) | (aec_1 << 8) | aec_2) >> 4;
uint16_t hts = (hts_h << 8) | hts_l;
uint16_t vts = (vts_h << 8) | vts_l;
aec = IM_MIN(aec, vts);
int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv);
int clocks_per_us = pclk_freq / 1000000;
@ -1207,9 +1215,9 @@ static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, floa
if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
&& (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0))), 4095), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((g_gain_db / 20.0) * fast_log(10.0))), 4095), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0))), 4095), 0);
int r_gain = IM_MAX(IM_MIN(fast_roundf(expf((r_gain_db / 20.0f) * M_LN10)), 4095), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(expf((g_gain_db / 20.0f) * M_LN10)), 4095), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(expf((b_gain_db / 20.0f) * M_LN10)), 4095), 0);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AWB_R_GAIN_H, r_gain >> 8);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AWB_R_GAIN_L, r_gain);
@ -1232,9 +1240,35 @@ static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db,
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AWB_B_GAIN_H, &blueh);
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AWB_B_GAIN_L, &bluel);
*r_gain_db = 20.0 * (fast_log(((redh & 0xF) << 8) | redl) / fast_log(10.0));
*g_gain_db = 20.0 * (fast_log(((greenh & 0xF) << 8) | greenl) / fast_log(10.0));
*b_gain_db = 20.0 * (fast_log(((blueh & 0xF) << 8) | bluel) / fast_log(10.0));
*r_gain_db = 20.0f * log10f(((redh & 0xF) << 8) | redl);
*g_gain_db = 20.0f * log10f(((greenh & 0xF) << 8) | greenl);
*b_gain_db = 20.0f * log10f(((blueh & 0xF) << 8) | bluel);
return ret;
}
static int set_auto_blc(sensor_t *sensor, int enable, int *regs) {
uint8_t reg;
int ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, BLC_CTRL_00, &reg);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, BLC_CTRL_00, (reg & 0xFE) | (enable != 0));
if ((enable == 0) && (regs != NULL)) {
for (uint32_t i = 0; i < sensor->hw_flags.blc_size; i++) {
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, BLACK_LEVEL_00_H + i, regs[i]);
}
}
return ret;
}
static int get_blc_regs(sensor_t *sensor, int *regs) {
int ret = 0;
for (uint32_t i = 0; i < sensor->hw_flags.blc_size; i++) {
uint8_t reg;
ret |= omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, BLACK_LEVEL_00_H + i, &reg);
regs[i] = reg;
}
return ret;
}
@ -1298,6 +1332,7 @@ static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef)
static int ioctl(sensor_t *sensor, int request, va_list ap) {
int ret = 0;
uint8_t reg;
switch (request) {
case IOCTL_SET_READOUT_WINDOW: {
@ -1343,7 +1378,6 @@ static int ioctl(sensor_t *sensor, int request, va_list ap) {
case IOCTL_WAIT_ON_AUTO_FOCUS: {
mp_uint_t start_tick = mp_hal_ticks_ms(), delay_ms = va_arg(ap, uint32_t);
for (;;) {
uint8_t reg;
ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AF_CMD_ACK, &reg);
if ((ret < 0) || (!reg)) {
break;
@ -1356,6 +1390,21 @@ static int ioctl(sensor_t *sensor, int request, va_list ap) {
break;
}
#endif
case IOCTL_SET_NIGHT_MODE: {
int enable = va_arg(ap, int);
ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_CTRL_00, &reg);
ret |= omv_i2c_writeb2(&sensor->i2c_bus, sensor->slv_addr, AEC_CTRL_00,
(reg & 0xFB) | ((enable != 0) << 2));
break;
}
case IOCTL_GET_NIGHT_MODE: {
int *enable = va_arg(ap, int *);
ret = omv_i2c_readb2(&sensor->i2c_bus, sensor->slv_addr, AEC_CTRL_00, &reg);
if (ret >= 0) {
*enable = reg & 0x4;
}
break;
}
default: {
ret = -1;
break;
@ -1385,6 +1434,8 @@ int ov5640_init(sensor_t *sensor) {
sensor->get_exposure_us = get_exposure_us;
sensor->set_auto_whitebal = set_auto_whitebal;
sensor->get_rgb_gain_db = get_rgb_gain_db;
sensor->set_auto_blc = set_auto_blc;
sensor->get_blc_regs = get_blc_regs;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_special_effect = set_special_effect;
@ -1401,6 +1452,7 @@ int ov5640_init(sensor_t *sensor) {
sensor->hw_flags.gs_bpp = 1;
sensor->hw_flags.rgb_swap = 0;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
sensor->hw_flags.blc_size = 8;
return 0;
}

View File

@ -87,9 +87,25 @@
#define TIMING_TC_REG_20 0x3820
#define TIMING_TC_REG_21 0x3821
#define AEC_CTRL_00 0x3A00
#define AEC_GAIN_CEILING_H 0x3A18
#define AEC_GAIN_CEILING_L 0x3A18
#define BLC_CTRL_00 0x4000
#define BLACK_LEVEL_00_H 0x402C
#define BLACK_LEVEL_00_L 0x402D
#define BLACK_LEVEL_01_H 0x402E
#define BLACK_LEVEL_01_L 0x402F
#define BLACK_LEVEL_10_H 0x4030
#define BLACK_LEVEL_10_L 0x4031
#define BLACK_LEVEL_11_H 0x4032
#define BLACK_LEVEL_11_L 0x4033
#define FORMAT_CONTROL 0x4300
#define VFIFO_HSIZE_H 0x4602

View File

@ -336,7 +336,9 @@ static int reset(sensor_t *sensor) {
}
// Delay 300 ms
mp_hal_delay_ms(300);
if (!sensor->disable_delays) {
mp_hal_delay_ms(300);
}
return ret;
}

View File

@ -196,7 +196,9 @@ static int reset(sensor_t *sensor) {
}
// Delay 300 ms
mp_hal_delay_ms(300);
if (!sensor->disable_delays) {
mp_hal_delay_ms(300);
}
return ret;
}
@ -379,24 +381,24 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG13, (reg & 0xFB) | ((enable != 0) << 2));
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 128.0), 1.0);
float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0f) * M_LN10), 128.0f), 1.0f);
int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
int gain_temp = fast_ceilf(logf(IM_MAX(gain / 2.0f, 1.0f)) / M_LN2);
int gain_hi = 0x3F >> (6 - gain_temp);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0f) * 16.0f), 15);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, REG15, &reg);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG15, (reg & 0xFC) | (gain_hi >> 4));
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 2.0);
float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0f) * M_LN10), 128.0f), 2.0f);
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, REG14, &reg);
ret |=
omv_i2c_writeb(&sensor->i2c_bus,
sensor->slv_addr,
REG14,
(reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4));
(reg & 0x8F) | ((fast_ceilf(logf(gain_ceiling) / M_LN2) - 1) << 4));
}
return ret;
@ -413,8 +415,8 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
(((reg15 >>
1) & 1) +
((reg15 >> 0) & 1) + ((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
*gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0));
float lo_gain = 1.0f + (((gain >> 0) & 0xF) / 16.0f);
*gain_db = 20.0f * log10f(hi_gain * lo_gain);
return ret;
}
@ -507,9 +509,9 @@ static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, floa
if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
&& (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0))), 255), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((g_gain_db / 20.0) * fast_log(10.0))), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0))), 255), 0);
int r_gain = IM_MAX(IM_MIN(fast_roundf(expf((r_gain_db / 20.0f) * M_LN10)), 255), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(expf((g_gain_db / 20.0f) * M_LN10)), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(expf((b_gain_db / 20.0f) * M_LN10)), 255), 0);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, BGAIN, b_gain);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, RGAIN, r_gain);
@ -527,9 +529,9 @@ static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db,
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, RGAIN, &red);
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, GGAIN, &green);
*r_gain_db = 20.0 * (fast_log(red) / fast_log(10.0));
*g_gain_db = 20.0 * (fast_log(green) / fast_log(10.0));
*b_gain_db = 20.0 * (fast_log(blue) / fast_log(10.0));
*r_gain_db = 20.0f * log10f(red);
*g_gain_db = 20.0f * log10f(green);
*b_gain_db = 20.0f * log10f(blue);
return ret;
}

View File

@ -163,7 +163,9 @@ static int reset(sensor_t *sensor) {
}
// Delay 300 ms
mp_hal_delay_ms(300);
if (!sensor->disable_delays) {
mp_hal_delay_ms(300);
}
return ret;
}
@ -346,20 +348,20 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM8, COM8_SET_AGC(reg, (enable != 0)));
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 32.0), 1.0);
float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0f) * M_LN10), 32.0f), 1.0f);
int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
int gain_temp = fast_ceilf(logf(IM_MAX(gain / 2.0f, 1.0f)) / M_LN2);
int gain_hi = 0xF >> (4 - gain_temp);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0f) * 16.0f), 15);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 32.0), 2.0);
float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0f) * M_LN10), 32.0f), 2.0f);
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, COM9, &reg);
ret |=
omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM9,
(reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4));
(reg & 0x8F) | ((fast_ceilf(logf(gain_ceiling) / M_LN2) - 1) << 4));
}
return ret;
@ -384,8 +386,8 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
// DISABLED
int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
*gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0));
float lo_gain = 1.0f + (((gain >> 0) & 0xF) / 16.0f);
*gain_db = 20.0f * log10f(hi_gain * lo_gain);
return ret;
}
@ -499,11 +501,11 @@ static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, floa
if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
&& (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, AWB_CTRL1, &reg);
float gain_div = (reg & 0x2) ? 64.0 : 128.0;
float gain_div = (reg & 0x2) ? 64.0f : 128.0f;
int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((g_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0);
int r_gain = IM_MAX(IM_MIN(fast_roundf(expf((r_gain_db / 20.0f) * M_LN10) * gain_div), 255), 0);
int g_gain = IM_MAX(IM_MIN(fast_roundf(expf((g_gain_db / 20.0f) * M_LN10) * gain_div), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(expf((b_gain_db / 20.0f) * M_LN10) * gain_div), 255), 0);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, BLUE, b_gain);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, RED, r_gain);
@ -534,11 +536,37 @@ static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db,
// DISABLED
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, AWB_CTRL1, &reg);
float gain_div = (reg & 0x2) ? 64.0 : 128.0;
float gain_div = (reg & 0x2) ? 64.0f : 128.0f;
*r_gain_db = 20.0 * (fast_log(red / gain_div) / fast_log(10.0));
*g_gain_db = 20.0 * (fast_log(green / gain_div) / fast_log(10.0));
*b_gain_db = 20.0 * (fast_log(blue / gain_div) / fast_log(10.0));
*r_gain_db = 20.0f * log10f(red / gain_div);
*g_gain_db = 20.0f * log10f(green / gain_div);
*b_gain_db = 20.0f * log10f(blue / gain_div);
return ret;
}
static int set_auto_blc(sensor_t *sensor, int enable, int *regs) {
uint8_t reg;
int ret = omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, COM13, &reg);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM13, COM13_SET_BLC(reg, (enable != 0)));
if ((enable == 0) && (regs != NULL)) {
for (uint32_t i = 0; i < sensor->hw_flags.blc_size; i++) {
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, ADOFF_B + i, regs[i]);
}
}
return ret;
}
static int get_blc_regs(sensor_t *sensor, int *regs) {
int ret = 0;
for (uint32_t i = 0; i < sensor->hw_flags.blc_size; i++) {
uint8_t reg;
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, ADOFF_B + i, &reg);
regs[i] = reg;
}
return ret;
}
@ -590,6 +618,38 @@ static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef)
return ret;
}
static int ioctl(sensor_t *sensor, int request, va_list ap) {
int ret = 0;
uint8_t reg;
switch (request) {
case IOCTL_SET_NIGHT_MODE: {
int enable = va_arg(ap, int);
ret = omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, COM5, &reg);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, COM5, COM5_SET_AFR(reg, (enable != 0)));
if (enable == 0) {
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, ADVFL, 0);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, ADVFH, 0);
}
break;
}
case IOCTL_GET_NIGHT_MODE: {
int *enable = va_arg(ap, int *);
ret = omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, COM5, &reg);
if (ret >= 0) {
*enable = reg & COM5_AFR;
}
break;
}
default: {
ret = -1;
break;
}
}
return ret;
}
int ov7725_init(sensor_t *sensor) {
// Initialize sensor structure.
sensor->reset = reset;
@ -609,10 +669,13 @@ int ov7725_init(sensor_t *sensor) {
sensor->get_exposure_us = get_exposure_us;
sensor->set_auto_whitebal = set_auto_whitebal;
sensor->get_rgb_gain_db = get_rgb_gain_db;
sensor->set_auto_blc = set_auto_blc;
sensor->get_blc_regs = get_blc_regs;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_special_effect = set_special_effect;
sensor->set_lens_correction = set_lens_correction;
sensor->ioctl = ioctl;
// Set sensor flags
sensor->hw_flags.vsync = 1;
@ -623,6 +686,7 @@ int ov7725_init(sensor_t *sensor) {
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 1;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
sensor->hw_flags.blc_size = 8;
return 0;
}

View File

@ -68,6 +68,7 @@
#define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */
#define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */
#define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */
#define COM5_SET_AFR(r, x) ((r & 0x7F) | ((x & 0x1) << 7))
#define COM6 0x0F /* Common Control 6 */
#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */
@ -184,6 +185,7 @@
#define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */
#define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */
#define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */
#define COM13_SET_BLC(r, x) ((r & 0x7F) | ((x & 0x1) << 7))
#define COM14 0x3F /* Common Control 14 */
#define COM15 0x40 /* Common Control 15 */

View File

@ -331,22 +331,22 @@ static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain
(reg & (~REG_COM8_AGC)) | ((enable != 0) ? REG_COM8_AGC : 0));
if ((enable == 0) && (!isnanf(gain_db)) && (!isinf(gain_db))) {
float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 128.0), 1.0);
float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0f) * M_LN10), 128.0f), 1.0f);
int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
int gain_temp = fast_ceilf(logf(IM_MAX(gain / 2.0f, 1.0f)) / M_LN2);
int gain_hi = 0x3F >> (6 - gain_temp);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0f) * 16.0f), 15);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG_GAIN, ((gain_hi & 0x0F) << 4) | (gain_lo << 0));
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, REG_VREF, &reg);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG_VREF, ((gain_hi & 0x30) << 2) | (reg & 0x3F));
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinf(gain_db_ceiling))) {
float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 2.0);
float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0f) * M_LN10), 128.0f), 2.0f);
ret |= omv_i2c_readb(&sensor->i2c_bus, sensor->slv_addr, REG_COM9, &reg);
ret |=
omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG_COM9,
(reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4));
(reg & 0x8F) | ((fast_ceilf(logf(gain_ceiling) / M_LN2) - 1) << 4));
}
return ret;
@ -376,8 +376,8 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) {
(((gain >>
9) & 1) +
((gain >> 8) & 1) + ((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
*gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0));
float lo_gain = 1.0f + (((gain >> 0) & 0xF) / 16.0f);
*gain_db = 20.0f * log10f(hi_gain * lo_gain);
return ret;
}
@ -486,8 +486,8 @@ static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, floa
if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
&& (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0)) * 128.0), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0)) * 128.0), 255), 0);
int r_gain = IM_MAX(IM_MIN(fast_roundf(expf((r_gain_db / 20.0f) * M_LN10) * 128.0f), 255), 0);
int b_gain = IM_MAX(IM_MIN(fast_roundf(expf((b_gain_db / 20.0f) * M_LN10) * 128.0f), 255), 0);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG_BLUE, b_gain);
ret |= omv_i2c_writeb(&sensor->i2c_bus, sensor->slv_addr, REG_RED, r_gain);
@ -515,8 +515,8 @@ static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db,
// }
// DISABLED
*r_gain_db = 20.0 * (fast_log(red / 128.0) / fast_log(10.0));
*b_gain_db = 20.0 * (fast_log(blue / 128.0) / fast_log(10.0));
*r_gain_db = 20.0f * log10f(red / 128.0f);
*b_gain_db = 20.0f * log10f(blue / 128.0f);
return ret;
}

View File

@ -314,7 +314,7 @@ static void auto_exposure(sensor_t *sensor) {
gain_target = 8;
}
//gain_target = IM_MIN(IM_MAX(fast_ceilf(GEP_target/expo_target), R_AE_MinGain), R_AE_MaxGain);
gain_db = 20 * (fast_log((float) gain_target) / fast_log(10.0));
gain_db = 20 * log10f((float) gain_target);
expo_target = IM_MIN(IM_MAX(fast_roundf(GEP_target / gain_target), R_AE_MinExpoTime), R_AE_MaxExpoTime);
#ifdef DEBUG_AE
printf("Gain Target: %ld (%d DB (x1000))\n", gain_target, (int) (gain_db * 1000));