Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/OPENMV_AE3/omv_boardconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ extern unsigned char OMV_BOARD_UID_ADDR[12]; // Unique address.
// Camera interface
#define OMV_CSI_BASE ((CPI_Type *) CPI_BASE)
#define OMV_CSI_CLK_FREQUENCY (24000000)
#define OMV_CSI_STATS_ENABLE (1)

#define OMV_CSI_D0_PIN (&omv_pin_CSI_D0)
#define OMV_CSI_D1_PIN (&omv_pin_CSI_D1)
Expand Down
1 change: 1 addition & 0 deletions boards/OPENMV_N6/omv_boardconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@
#define OMV_CSI_DMA_XFER_PORTS (DMA_SRC_ALLOCATED_PORT1 | DMA_DEST_ALLOCATED_PORT0)
#define OMV_CSI_HW_CROP_ENABLE (1)
#define OMV_CSI_MAX_DEVICES (3)
#define OMV_CSI_STATS_ENABLE (1)

#define OMV_CSI_D0_PIN (&omv_pin_A1_DCMI)
#define OMV_CSI_D1_PIN (&omv_pin_A10_DCMI)
Expand Down
40 changes: 40 additions & 0 deletions common/omv_csi.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
#define OMV_CSI_CLK_TOLERANCE (500000)
#endif

#ifndef OMV_CSI_STATS_TAU_MS
#define OMV_CSI_STATS_TAU_MS (250)
#endif

#ifndef __weak
#define __weak __attribute__((weak))
#endif
Expand Down Expand Up @@ -322,6 +326,12 @@ __weak int omv_csi_reset(omv_csi_t *csi, bool hard) {
NULL, NULL
};

#if defined(OMV_CSI_STATS_ENABLE)
// Enable collecting RGB stats.
csi->stats_enabled = true;
memset(&csi->stats, 0, sizeof(omv_csi_stats_t));
#endif // defined(OMV_CSI_STATS_ENABLE)

// Restore shutdown state on reset.
if (!csi->power_on) {
omv_csi_shutdown(csi, false);
Expand Down Expand Up @@ -1147,6 +1157,36 @@ __weak int omv_csi_get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_ga
return 0;
}

#if defined(OMV_CSI_STATS_ENABLE)
void omv_csi_stats_update(omv_csi_t *csi, uint32_t *r, uint32_t *g, uint32_t *b, uint32_t ms) {
omv_csi_stats_t *stats = &csi->stats;

if (!stats->initialized) {
stats->initialized = true;
stats->last_ms = ms;
stats->r_avg = *r;
stats->g_avg = *g;
stats->b_avg = *b;
} else {
uint32_t dt_ms = ms - stats->last_ms;
// Continuous-time EMA gain for elapsed dt: alpha = 1 - exp(-dt/τ)
float alpha = IM_CLAMP(1.0f - expf(-((float) dt_ms) / OMV_CSI_STATS_TAU_MS), 0.0f, 1.0f);
stats->last_ms = ms;
stats->r_avg += alpha * (*r - stats->r_avg);
stats->g_avg += alpha * (*g - stats->g_avg);
stats->b_avg += alpha * (*b - stats->b_avg);
}
}

void omv_csi_get_stats(omv_csi_t *csi, uint32_t *r, uint32_t *g, uint32_t *b) {
omv_csi_stats_t *stats = &csi->stats;

*r = fast_roundf(stats->r_avg);
*g = fast_roundf(stats->g_avg);
*b = fast_roundf(stats->b_avg);
}
#endif // defined(OMV_CSI_STATS_ENABLE)

__weak int omv_csi_set_auto_blc(omv_csi_t *csi, int enable, int *regs) {
// Check if the control is supported.
if (csi->set_auto_blc == NULL) {
Expand Down
23 changes: 23 additions & 0 deletions common/omv_csi.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,16 @@ typedef struct _omv_clk {
int (*set_freq) (omv_clk_t *csi, uint32_t freq);
} omv_clk_t;

#if defined(OMV_CSI_STATS_ENABLE)
typedef struct omv_csi_stats {
bool initialized;
uint32_t last_ms;
float r_avg;
float g_avg;
float b_avg;
} omv_csi_stats_t;
#endif // defined(OMV_CSI_STATS_ENABLE)

typedef struct _omv_csi {
uint32_t chip_id; // Sensor ID 32 bits.
uint8_t slv_addr; // Sensor I2C slave address.
Expand Down Expand Up @@ -369,6 +379,11 @@ typedef struct _omv_csi {
uint32_t reset_time_ms; // To track elapsed time since hard-reset.
uint32_t power_time_ms; // To track elapsed time since power on.

#if defined(OMV_CSI_STATS_ENABLE)
bool stats_enabled; // AWB stats enabled.
omv_csi_stats_t stats; // AWB stats struct.
#endif // defined(OMV_CSI_STATS_ENABLE)

#ifdef OMV_CSI_PORT_BITS
// Additional port-specific members like device base pointer,
// DMA handles, and additional I/Os, are included directly here.
Expand Down Expand Up @@ -534,6 +549,14 @@ int omv_csi_set_auto_whitebal(omv_csi_t *csi, int enable, float r_gain_db, float
// Get the rgb gain values.
int omv_csi_get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_gain_db, float *b_gain_db);

#if defined(OMV_CSI_STATS_ENABLE)
// Update RGB moving average struct.
void omv_csi_stats_update(omv_csi_t *csi, uint32_t *r, uint32_t *g, uint32_t *b, uint32_t ms);

// Get RGB moving average values.
void omv_csi_get_stats(omv_csi_t *csi, uint32_t *r, uint32_t *g, uint32_t *b);
#endif // defined(OMV_CSI_STATS_ENABLE)

// Enable auto blc (black level calibration) or set from previous calibration.
int omv_csi_set_auto_blc(omv_csi_t *csi, int enable, int *regs);

Expand Down
17 changes: 17 additions & 0 deletions drivers/sensors/pag7936.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,21 @@ static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
return ret;
}

static int set_auto_whitebal(omv_csi_t *csi, int enable, float r_gain_db, float g_gain_db, float b_gain_db) {
csi->stats_enabled = enable;
return 0;
}

static int get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_gain_db, float *b_gain_db) {
uint32_t r, g, b;
omv_csi_get_stats(csi, &r, &g, &b);

*r_gain_db = 20.0f * log10f(IM_DIV((float) g, r));
*g_gain_db = 0.0f;
*b_gain_db = 20.0f * log10f(IM_DIV((float) g, b));
return 0;
}

static int set_hmirror(omv_csi_t *csi, int enable) {
uint8_t reg;
int ret = omv_i2c_readb2(csi->i2c, csi->slv_addr, TG_FLIP, &reg);
Expand Down Expand Up @@ -723,6 +738,8 @@ int pag7936_init(omv_csi_t *csi) {
csi->get_gain_db = get_gain_db;
csi->set_auto_exposure = set_auto_exposure;
csi->get_exposure_us = get_exposure_us;
csi->set_auto_whitebal = set_auto_whitebal;
csi->get_rgb_gain_db = get_rgb_gain_db;
csi->set_hmirror = set_hmirror;
csi->set_vflip = set_vflip;

Expand Down
17 changes: 17 additions & 0 deletions drivers/sensors/ps5520.c
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,21 @@ static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
return ret;
}

static int set_auto_whitebal(omv_csi_t *csi, int enable, float r_gain_db, float g_gain_db, float b_gain_db) {
csi->stats_enabled = enable;
return 0;
}

static int get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_gain_db, float *b_gain_db) {
uint32_t r, g, b;
omv_csi_get_stats(csi, &r, &g, &b);

*r_gain_db = 20.0f * log10f(IM_DIV((float) g, r));
*g_gain_db = 0.0f;
*b_gain_db = 20.0f * log10f(IM_DIV((float) g, b));
return 0;
}

static int set_hmirror(omv_csi_t *csi, int enable) {
uint8_t reg1, reg2;
uint16_t hsize;
Expand Down Expand Up @@ -1590,6 +1605,8 @@ int ps5520_init(omv_csi_t *csi) {
csi->get_gain_db = get_gain_db;
csi->set_auto_exposure = set_auto_exposure;
csi->get_exposure_us = get_exposure_us;
csi->set_auto_whitebal = set_auto_whitebal;
csi->get_rgb_gain_db = get_rgb_gain_db;
csi->set_hmirror = set_hmirror;
csi->set_vflip = set_vflip;

Expand Down
20 changes: 13 additions & 7 deletions ports/alif/omv_csi.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,7 @@ static uint32_t omv_csi_get_fb_offset(omv_csi_t *csi) {
int alif_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
CPI_Type *cpi = csi->base;
framebuffer_t *fb = csi->fb;

vbuffer_t *buffer = NULL;
static uint32_t frames = 0;
static uint32_t r_stat, gb_stat, gr_stat, b_stat;

// Configure and re/start the capture if it's not alrady active
// and there are no pending buffers (from non-blocking capture).
Expand Down Expand Up @@ -397,13 +394,22 @@ int alif_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
// Set the target pixel format before debayer.
dst_image->pixfmt = fb->pixfmt;

// Update AWB stats every n frames.
if ((frames++ % 100) == 0) {
omv_csi_ioctl(csi, OMV_CSI_IOCTL_GET_RGB_STATS, &r_stat, &gb_stat, &gr_stat, &b_stat);
uint32_t r, g, b;
if (csi->stats_enabled) {
uint32_t gb, gr;
int ret = omv_csi_ioctl(csi, OMV_CSI_IOCTL_GET_RGB_STATS, &r, &gb, &gr, &b);
if (ret != 0) {
return ret;
}

g = (gb + gr) / 2;
omv_csi_stats_update(csi, &r, &g, &b, mp_hal_ticks_ms());
}

omv_csi_get_stats(csi, &r, &g, &b);

// Debayer frame.
imlib_debayer_image_awb(dst_image, &src_image, false, r_stat, (gb_stat + gr_stat) / 2, b_stat);
imlib_debayer_image_awb(dst_image, &src_image, false, r, g, b);
}
return 0;
}
Expand Down
6 changes: 3 additions & 3 deletions ports/stm32/omv_csi.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static bool stm_csi_is_active(omv_csi_t *csi) {
int stm_csi_isp_reset(omv_csi_t *csi) {
#if USE_DCMIPP
if (csi->mipi_if) {
return stm_isp_update_gamma_table(&csi->dcmipp, DCMIPP_PIPE, 0.0f, 1.0f, 2.2f);
return stm_isp_update_gamma_table(csi, DCMIPP_PIPE, 0.0f, 1.0f, 2.2f);
}
#endif // USE_DCMIPP
return 0;
Expand Down Expand Up @@ -278,7 +278,7 @@ static int stm_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
csi->dcmipp.PipeState[i] = HAL_DCMIPP_PIPE_STATE_RESET;
}
// Configure the pixel processing pipeline.
if (stm_isp_config_pipeline(&csi->dcmipp, DCMIPP_PIPE, csi->pixformat, csi->raw_output)) {
if (stm_isp_init(csi, DCMIPP_PIPE, csi->pixformat, csi->raw_output)) {
return OMV_CSI_ERROR_CSI_INIT_FAILED;
}
#endif
Expand Down Expand Up @@ -760,7 +760,7 @@ static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {

#if USE_DCMIPP
if (csi->raw_output) {
float luminance = stm_isp_update_awb(&csi->dcmipp, DCMIPP_PIPE, fb->u * fb->v);
float luminance = stm_isp_update_awb(csi, DCMIPP_PIPE, fb->u * fb->v);
if (csi->ioctl) {
omv_csi_ioctl(csi, OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance));
}
Expand Down
56 changes: 31 additions & 25 deletions ports/stm32/stm_isp.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,33 @@

#include <string.h>
#include "imlib.h"
#include "py/mphal.h"
#include "stm_isp.h"
#include "omv_boardconfig.h"

#ifdef DCMIPP
float stm_isp_update_awb(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, uint32_t n_pixels) {
float stm_isp_update_awb(omv_csi_t *csi, uint32_t pipe, uint32_t n_pixels) {
uint32_t avg[3];
uint32_t shift[3];
uint32_t multi[3];

for (int i = 0; i < 3; i++) {
// DCMIPP_STATEXT_MODULE1
HAL_DCMIPP_PIPE_GetISPAccumulatedStatisticsCounter(dcmipp, pipe, i + 1, &avg[i]);
if (csi->stats_enabled) {
for (int i = 0; i < 3; i++) {
// DCMIPP_STATEXT_MODULE1
HAL_DCMIPP_PIPE_GetISPAccumulatedStatisticsCounter(&csi->dcmipp, pipe, i + 1, &avg[i]);
}

// Averages are collected from bayer components (4R 2G 4B).
avg[0] = OMV_MAX((avg[0] * 256 * 4) / n_pixels, 1);
avg[1] = OMV_MAX((avg[1] * 256 * 2) / n_pixels, 1);
avg[2] = OMV_MAX((avg[2] * 256 * 4) / n_pixels, 1);
omv_csi_stats_update(csi, &avg[0], &avg[1], &avg[2], mp_hal_ticks_ms());
}

// Averages are collected from bayer components (4R 2G 4B).
avg[0] = OMV_MAX((avg[0] * 256 * 4) / n_pixels, 1);
avg[1] = OMV_MAX((avg[1] * 256 * 2) / n_pixels, 1);
avg[2] = OMV_MAX((avg[2] * 256 * 4) / n_pixels, 1);
omv_csi_get_stats(csi, &avg[0], &avg[1], &avg[2]);

// Compute global luminance
float luminance = avg[0] * 0.299 + avg[1] * 0.587 + avg[2] * 0.114;
float luminance = avg[0] * 0.299f + avg[1] * 0.587f + avg[2] * 0.114f;

// Calculate average and exposure factors for each channel (R, G, B)
for (int i = 0; i < 3; i++) {
Expand All @@ -75,13 +81,12 @@ float stm_isp_update_awb(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, uint32_t n
.MultiplierBlue = multi[2],
};

HAL_DCMIPP_PIPE_SetISPExposureConfig(dcmipp, pipe, &expcfg);
HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmipp, pipe, &expcfg);

return luminance;
}

int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
pixformat_t pixformat, bool raw_output) {
int stm_isp_init(omv_csi_t *csi, uint32_t pipe, pixformat_t pixformat, bool raw_output) {
// Configure the pixel processing pipeline.
DCMIPP_PipeConfTypeDef pcfg = {
.FrameRate = DCMIPP_FRAME_RATE_ALL
Expand All @@ -97,7 +102,7 @@ int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
return -1;
}

if (HAL_DCMIPP_PIPE_SetConfig(dcmipp, pipe, &pcfg) != HAL_OK) {
if (HAL_DCMIPP_PIPE_SetConfig(&csi->dcmipp, pipe, &pcfg) != HAL_OK) {
return -1;
}

Expand All @@ -115,8 +120,8 @@ int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
.EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE,
};

if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(dcmipp, pipe, &rawcfg) != HAL_OK ||
HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(dcmipp, pipe) != HAL_OK) {
if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(&csi->dcmipp, pipe, &rawcfg) != HAL_OK ||
HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&csi->dcmipp, pipe) != HAL_OK) {
return -1;
}

Expand All @@ -129,8 +134,8 @@ int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
.MultiplierBlue = 128,
};

if (HAL_DCMIPP_PIPE_SetISPExposureConfig(dcmipp, pipe, &expcfg) != HAL_OK ||
HAL_DCMIPP_PIPE_EnableISPExposure(dcmipp, pipe) != HAL_OK) {
if (HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmipp, pipe, &expcfg) != HAL_OK ||
HAL_DCMIPP_PIPE_EnableISPExposure(&csi->dcmipp, pipe) != HAL_OK) {
return -1;
}

Expand All @@ -148,29 +153,29 @@ int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
}

for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) {
if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(dcmipp,
pipe, i,
if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(&csi->dcmipp, pipe, i,
&statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) {
return -1;
}

if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(dcmipp, pipe, i) != HAL_OK) {
if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(&csi->dcmipp, pipe, i) != HAL_OK) {
return -1;
}
}

if (HAL_DCMIPP_PIPE_SetISPBadPixelRemovalConfig(dcmipp, pipe, DCMIPP_BAD_PXL_REM_SRENGTH_4) != HAL_OK) {
if (HAL_DCMIPP_PIPE_SetISPBadPixelRemovalConfig(&csi->dcmipp, pipe,
DCMIPP_BAD_PXL_REM_SRENGTH_4) != HAL_OK) {
return -1;
}

if (HAL_DCMIPP_PIPE_EnableISPBadPixelRemoval(dcmipp, pipe) != HAL_OK) {
if (HAL_DCMIPP_PIPE_EnableISPBadPixelRemoval(&csi->dcmipp, pipe) != HAL_OK) {
return -1;
}

return 0;
}

int stm_isp_update_gamma_table(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
int stm_isp_update_gamma_table(omv_csi_t *csi, uint32_t pipe,
float brightness, float contrast, float gamma) {
uint8_t g_tab[9]; // sizeof(DCMIPP_ContrastConfTypeDef)

Expand All @@ -182,11 +187,12 @@ int stm_isp_update_gamma_table(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe,
g_tab[i] = IM_CLAMP(gain, 0, 32);
}

if (HAL_DCMIPP_PIPE_SetISPCtrlContrastConfig(dcmipp, pipe, (DCMIPP_ContrastConfTypeDef *) &g_tab) != HAL_OK) {
if (HAL_DCMIPP_PIPE_SetISPCtrlContrastConfig(&csi->dcmipp, pipe,
(DCMIPP_ContrastConfTypeDef *) &g_tab) != HAL_OK) {
return -1;
}

if (HAL_DCMIPP_PIPE_EnableISPCtrlContrast(dcmipp, pipe) != HAL_OK) {
if (HAL_DCMIPP_PIPE_EnableISPCtrlContrast(&csi->dcmipp, pipe) != HAL_OK) {
return -1;
}

Expand Down
Loading