From 5bbe25c20173e64373ff712ee64e470741b61f30 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sun, 14 Feb 2021 21:10:23 +0200 Subject: [PATCH] Replace VSYNC output pin with callback. --- src/omv/modules/py_sensor.c | 140 ++++++++++++++++++++++++----------- src/omv/ports/stm32/sensor.c | 25 ++++--- src/omv/ports/stm32/sensor.h | 9 +-- 3 files changed, 115 insertions(+), 59 deletions(-) diff --git a/src/omv/modules/py_sensor.c b/src/omv/modules/py_sensor.c index 96ecbea46..ffb1a1d2b 100644 --- a/src/omv/modules/py_sensor.c +++ b/src/omv/modules/py_sensor.c @@ -27,9 +27,11 @@ #include "framebuffer.h" extern sensor_t sensor; +static mp_obj_t vsync_callback = mp_const_none; #if MICROPY_PY_IMU -static void do_auto_rotation(int pitch_deadzone, int roll_activezone) { +static void do_auto_rotation(int pitch_deadzone, int roll_activezone) +{ if (sensor_get_auto_rotation()) { float pitch = py_imu_pitch_rotation(); if (((pitch <= (90 - pitch_deadzone)) || ((90 + pitch_deadzone) < pitch)) @@ -69,7 +71,8 @@ static mp_obj_t py_sensor__init__() return mp_const_none; } -static mp_obj_t py_sensor_reset() { +static mp_obj_t py_sensor_reset() +{ PY_ASSERT_FALSE_MSG(sensor_reset() != 0, "Reset Failed"); #if MICROPY_PY_IMU // +-10 degree dead-zone around pitch 90/270. @@ -81,17 +84,20 @@ static mp_obj_t py_sensor_reset() { return mp_const_none; } -static mp_obj_t py_sensor_sleep(mp_obj_t enable) { +static mp_obj_t py_sensor_sleep(mp_obj_t enable) +{ PY_ASSERT_FALSE_MSG(sensor_sleep(mp_obj_is_true(enable)) != 0, "Sleep Failed"); return mp_const_none; } -static mp_obj_t py_sensor_shutdown(mp_obj_t enable) { +static mp_obj_t py_sensor_shutdown(mp_obj_t enable) +{ PY_ASSERT_FALSE_MSG(sensor_shutdown(mp_obj_is_true(enable)) != 0, "Shutdown Failed"); return mp_const_none; } -static mp_obj_t py_sensor_flush() { +static mp_obj_t py_sensor_flush() +{ fb_update_jpeg_buffer(); return mp_const_none; } @@ -166,7 +172,8 @@ static mp_obj_t py_sensor_get_fb() return py_image_from_struct(&image); } -static mp_obj_t py_sensor_get_id() { +static mp_obj_t py_sensor_get_id() +{ return mp_obj_new_int(sensor_get_id()); } @@ -220,42 +227,48 @@ static mp_obj_t py_sensor_dealloc_extra_fb() return mp_const_none; } -static mp_obj_t py_sensor_set_pixformat(mp_obj_t pixformat) { +static mp_obj_t py_sensor_set_pixformat(mp_obj_t pixformat) +{ if (sensor_set_pixformat(mp_obj_get_int(pixformat)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Pixel format is not supported!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_pixformat() { +static mp_obj_t py_sensor_get_pixformat() +{ if (sensor.pixformat == PIXFORMAT_INVALID) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Pixel format not set yet!")); } return mp_obj_new_int(sensor.pixformat); } -static mp_obj_t py_sensor_set_framesize(mp_obj_t framesize) { +static mp_obj_t py_sensor_set_framesize(mp_obj_t framesize) +{ if (sensor_set_framesize(mp_obj_get_int(framesize)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to set framesize!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_framesize() { +static mp_obj_t py_sensor_get_framesize() +{ if (sensor.framesize == FRAMESIZE_INVALID) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Frame size not set yet!")); } return mp_obj_new_int(sensor.framesize); } -static mp_obj_t py_sensor_set_framerate(mp_obj_t framerate) { +static mp_obj_t py_sensor_set_framerate(mp_obj_t framerate) +{ if (sensor_set_framerate(mp_obj_get_int(framerate)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to set framerate!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_framerate() { +static mp_obj_t py_sensor_get_framerate() +{ if (sensor.framerate == 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Frame rate not set yet!")); } @@ -312,7 +325,8 @@ static mp_obj_t py_sensor_get_windowing() mp_obj_new_int(framebuffer_get_v())}); } -static mp_obj_t py_sensor_set_gainceiling(mp_obj_t gainceiling) { +static mp_obj_t py_sensor_set_gainceiling(mp_obj_t gainceiling) +{ gainceiling_t gain; switch (mp_obj_get_int(gainceiling)) { case 2: @@ -347,28 +361,32 @@ static mp_obj_t py_sensor_set_gainceiling(mp_obj_t gainceiling) { return mp_const_true; } -static mp_obj_t py_sensor_set_brightness(mp_obj_t brightness) { +static mp_obj_t py_sensor_set_brightness(mp_obj_t brightness) +{ if (sensor_set_brightness(mp_obj_get_int(brightness)) != 0) { return mp_const_false; } return mp_const_true; } -static mp_obj_t py_sensor_set_contrast(mp_obj_t contrast) { +static mp_obj_t py_sensor_set_contrast(mp_obj_t contrast) +{ if (sensor_set_contrast(mp_obj_get_int(contrast)) != 0) { return mp_const_false; } return mp_const_true; } -static mp_obj_t py_sensor_set_saturation(mp_obj_t saturation) { +static mp_obj_t py_sensor_set_saturation(mp_obj_t saturation) +{ if (sensor_set_saturation(mp_obj_get_int(saturation)) != 0) { return mp_const_false; } return mp_const_true; } -static mp_obj_t py_sensor_set_quality(mp_obj_t qs) { +static mp_obj_t py_sensor_set_quality(mp_obj_t qs) +{ int q = mp_obj_get_int(qs); PY_ASSERT_TRUE((q >= 0 && q <= 100)); @@ -380,14 +398,16 @@ static mp_obj_t py_sensor_set_quality(mp_obj_t qs) { return mp_const_true; } -static mp_obj_t py_sensor_set_colorbar(mp_obj_t enable) { +static mp_obj_t py_sensor_set_colorbar(mp_obj_t enable) +{ if (sensor_set_colorbar(mp_obj_is_true(enable)) != 0) { return mp_const_false; } return mp_const_true; } -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_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), NAN); float gain_db_ceiling = py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db_ceiling), NAN); @@ -397,7 +417,8 @@ static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_ma return mp_const_none; } -static mp_obj_t py_sensor_get_gain_db() { +static mp_obj_t py_sensor_get_gain_db() +{ float gain_db; if (sensor_get_gain_db(&gain_db) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); @@ -405,7 +426,8 @@ static mp_obj_t py_sensor_get_gain_db() { return mp_obj_new_float(gain_db); } -static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { +static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ int exposure_us = py_helper_keyword_int(n_args, args, 1, 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) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); @@ -413,7 +435,8 @@ static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, m return mp_const_none; } -static mp_obj_t py_sensor_get_exposure_us() { +static mp_obj_t py_sensor_get_exposure_us() +{ int exposure_us; if (sensor_get_exposure_us(&exposure_us) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); @@ -421,7 +444,8 @@ static mp_obj_t py_sensor_get_exposure_us() { 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) { +static mp_obj_t py_sensor_set_auto_whitebal(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ int enable = mp_obj_get_int(args[0]); float rgb_gain_db[3] = {NAN, NAN, NAN}; py_helper_keyword_float_array(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_gain_db), rgb_gain_db, 3); @@ -431,7 +455,8 @@ static mp_obj_t py_sensor_set_auto_whitebal(uint n_args, const mp_obj_t *args, m return mp_const_none; } -static mp_obj_t py_sensor_get_rgb_gain_db() { +static mp_obj_t py_sensor_get_rgb_gain_db() +{ float r_gain_db = 0.0, g_gain_db = 0.0, b_gain_db = 0.0; if (sensor_get_rgb_gain_db(&r_gain_db, &g_gain_db, &b_gain_db) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); @@ -439,58 +464,68 @@ static mp_obj_t py_sensor_get_rgb_gain_db() { return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_float(r_gain_db), mp_obj_new_float(g_gain_db), mp_obj_new_float(b_gain_db)}); } -static mp_obj_t py_sensor_set_hmirror(mp_obj_t enable) { +static mp_obj_t py_sensor_set_hmirror(mp_obj_t enable) +{ if (sensor_set_hmirror(mp_obj_is_true(enable)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_hmirror() { +static mp_obj_t py_sensor_get_hmirror() +{ return mp_obj_new_bool(sensor_get_hmirror()); } -static mp_obj_t py_sensor_set_vflip(mp_obj_t enable) { +static mp_obj_t py_sensor_set_vflip(mp_obj_t enable) +{ if (sensor_set_vflip(mp_obj_is_true(enable)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Sensor control failed!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_vflip() { +static mp_obj_t py_sensor_get_vflip() +{ return mp_obj_new_bool(sensor_get_vflip()); } -static mp_obj_t py_sensor_set_transpose(mp_obj_t enable) { +static mp_obj_t py_sensor_set_transpose(mp_obj_t enable) +{ if (sensor_set_transpose(mp_obj_is_true(enable)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Cannot transpose in JPEG mode!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_transpose() { +static mp_obj_t py_sensor_get_transpose() +{ return mp_obj_new_bool(sensor_get_transpose()); } -static mp_obj_t py_sensor_set_auto_rotation(mp_obj_t enable) { +static mp_obj_t py_sensor_set_auto_rotation(mp_obj_t enable) +{ if (sensor_set_auto_rotation(mp_obj_is_true(enable)) != 0) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Cannot auto rotate in JPEG mode!")); } return mp_const_none; } -static mp_obj_t py_sensor_get_auto_rotation() { +static mp_obj_t py_sensor_get_auto_rotation() +{ return mp_obj_new_bool(sensor_get_auto_rotation()); } -static mp_obj_t py_sensor_set_special_effect(mp_obj_t sde) { +static mp_obj_t py_sensor_set_special_effect(mp_obj_t sde) +{ if (sensor_set_special_effect(mp_obj_get_int(sde)) != 0) { return mp_const_false; } return mp_const_true; } -static mp_obj_t py_sensor_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp_obj_t coef) { +static mp_obj_t py_sensor_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp_obj_t coef) +{ if (sensor_set_lens_correction(mp_obj_is_true(enable), mp_obj_get_int(radi), mp_obj_get_int(coef)) != 0) { return mp_const_false; @@ -498,10 +533,23 @@ static mp_obj_t py_sensor_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp return mp_const_true; } -static mp_obj_t py_sensor_set_vsync_output(mp_obj_t pin_obj) { - pin_obj_t *pin = pin_obj; - sensor_set_vsync_output(pin->gpio, pin->pin_mask); - return mp_const_true; +static void sensor_vsync_callback(uint32_t vsync) +{ + if (mp_obj_is_callable(vsync_callback)) { + mp_call_function_1(vsync_callback, mp_obj_new_int(vsync)); + } +} + +static mp_obj_t py_sensor_set_vsync_callback(mp_obj_t vsync_callback_obj) +{ + if (!mp_obj_is_callable(vsync_callback_obj)) { + vsync_callback = mp_const_none; + sensor_set_vsync_callback(NULL); + } else { + vsync_callback = vsync_callback_obj; + sensor_set_vsync_callback(sensor_vsync_callback); + } + return mp_const_none; } static mp_obj_t py_sensor_ioctl(uint n_args, const mp_obj_t *args) @@ -717,7 +765,8 @@ static mp_obj_t py_sensor_ioctl(uint n_args, const mp_obj_t *args) return ret_obj; } -static mp_obj_t py_sensor_set_color_palette(mp_obj_t palette_obj) { +static mp_obj_t py_sensor_set_color_palette(mp_obj_t palette_obj) +{ int palette = mp_obj_get_int(palette_obj); switch (palette) { case COLOR_PALETTE_RAINBOW: @@ -733,7 +782,8 @@ static mp_obj_t py_sensor_set_color_palette(mp_obj_t palette_obj) { return mp_const_none; } -static mp_obj_t py_sensor_get_color_palette() { +static mp_obj_t py_sensor_get_color_palette() +{ const uint16_t *palette = sensor_get_color_palette(); if (palette == rainbow_table) { return mp_obj_new_int(COLOR_PALETTE_RAINBOW); @@ -743,12 +793,14 @@ static mp_obj_t py_sensor_get_color_palette() { return mp_const_none; } -static mp_obj_t py_sensor_write_reg(mp_obj_t addr, mp_obj_t val) { +static mp_obj_t py_sensor_write_reg(mp_obj_t addr, mp_obj_t val) +{ sensor_write_reg(mp_obj_get_int(addr), mp_obj_get_int(val)); return mp_const_none; } -static mp_obj_t py_sensor_read_reg(mp_obj_t addr) { +static mp_obj_t py_sensor_read_reg(mp_obj_t addr) +{ return mp_obj_new_int(sensor_read_reg(mp_obj_get_int(addr))); } @@ -795,7 +847,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_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); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vsync_output_obj, py_sensor_set_vsync_output); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vsync_callback_obj, py_sensor_set_vsync_callback); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_sensor_ioctl_obj, 1, 5, py_sensor_ioctl); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_color_palette_obj, py_sensor_set_color_palette); STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_color_palette_obj, py_sensor_get_color_palette); @@ -935,7 +987,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_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 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_set_vsync_output), (mp_obj_t)&py_sensor_set_vsync_output_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_vsync_callback), (mp_obj_t)&py_sensor_set_vsync_callback_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&py_sensor_ioctl_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_color_palette), (mp_obj_t)&py_sensor_set_color_palette_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_color_palette), (mp_obj_t)&py_sensor_get_color_palette_obj }, diff --git a/src/omv/ports/stm32/sensor.c b/src/omv/ports/stm32/sensor.c index c0f043d9f..1c7f7e5d5 100644 --- a/src/omv/ports/stm32/sensor.c +++ b/src/omv/ports/stm32/sensor.c @@ -239,6 +239,8 @@ void sensor_init0() cambus_init(&sensor.bus, ISC_I2C_ID, ISC_I2C_SPEED); #endif + // Disable VSYNC IRQ and callback + sensor_set_vsync_callback(NULL); } int sensor_init() @@ -491,7 +493,7 @@ int sensor_reset() #else sensor.auto_rotation = false; #endif // MICROPY_PY_IMU - sensor.vsync_gpio = NULL; + sensor.vsync_callback= NULL; // Reset default color palette. sensor.color_palette = rainbow_table; @@ -959,13 +961,17 @@ int sensor_ioctl(int request, ... /* arg */) return ret; } -int sensor_set_vsync_output(GPIO_TypeDef *gpio, uint32_t pin) +int sensor_set_vsync_callback(vsync_cb_t vsync_cb) { - sensor.vsync_pin = pin; - sensor.vsync_gpio = gpio; - // Enable VSYNC EXTI IRQ - NVIC_SetPriority(DCMI_VSYNC_IRQN, IRQ_PRI_EXTINT); - HAL_NVIC_EnableIRQ(DCMI_VSYNC_IRQN); + sensor.vsync_callback = vsync_cb; + if (sensor.vsync_callback == NULL) { + // Disable VSYNC EXTI IRQ + HAL_NVIC_DisableIRQ(DCMI_VSYNC_IRQN); + } else { + // Enable VSYNC EXTI IRQ + NVIC_SetPriority(DCMI_VSYNC_IRQN, IRQ_PRI_EXTINT); + HAL_NVIC_EnableIRQ(DCMI_VSYNC_IRQN); + } return 0; } @@ -983,9 +989,8 @@ const uint16_t *sensor_get_color_palette() void DCMI_VsyncExtiCallback() { __HAL_GPIO_EXTI_CLEAR_FLAG(1 << DCMI_VSYNC_IRQ_LINE); - if (sensor.vsync_gpio != NULL) { - HAL_GPIO_WritePin(sensor.vsync_gpio, sensor.vsync_pin, - !HAL_GPIO_ReadPin(DCMI_VSYNC_PORT, DCMI_VSYNC_PIN)); + if (sensor.vsync_callback != NULL) { + sensor.vsync_callback(HAL_GPIO_ReadPin(DCMI_VSYNC_PORT, DCMI_VSYNC_PIN)); } } diff --git a/src/omv/ports/stm32/sensor.h b/src/omv/ports/stm32/sensor.h index 9498d81d5..9113d5dee 100644 --- a/src/omv/ports/stm32/sensor.h +++ b/src/omv/ports/stm32/sensor.h @@ -139,6 +139,7 @@ typedef enum { #define SENSOR_HW_FLAGS_CLR(s, x) ((s)->hw_flags &= ~(1<