mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #2736 from openmv/refactor_csi_clock
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
common/csi: Decouple the clock from main CSI state.
This commit is contained in:
commit
284c8e184a
@ -273,7 +273,7 @@ extern unsigned char OMV_BOARD_UID_ADDR[12]; // Unique address.
|
|||||||
|
|
||||||
// Camera interface
|
// Camera interface
|
||||||
#define OMV_CSI_BASE ((CPI_Type *) CPI_BASE)
|
#define OMV_CSI_BASE ((CPI_Type *) CPI_BASE)
|
||||||
#define OMV_CSI_CLK_FREQUENCY (12000000)
|
#define OMV_CSI_CLK_FREQUENCY (24000000)
|
||||||
|
|
||||||
#define OMV_CSI_D0_PIN (&omv_pin_CSI_D0)
|
#define OMV_CSI_D0_PIN (&omv_pin_CSI_D0)
|
||||||
#define OMV_CSI_D1_PIN (&omv_pin_CSI_D1)
|
#define OMV_CSI_D1_PIN (&omv_pin_CSI_D1)
|
||||||
|
|||||||
@ -265,7 +265,7 @@
|
|||||||
|
|
||||||
// Camera Interface
|
// Camera Interface
|
||||||
#define OMV_CSI_CLK_SOURCE (OMV_CSI_CLK_SOURCE_TIM)
|
#define OMV_CSI_CLK_SOURCE (OMV_CSI_CLK_SOURCE_TIM)
|
||||||
#define OMV_CSI_CLK_FREQUENCY (12000000)
|
#define OMV_CSI_CLK_FREQUENCY (24000000)
|
||||||
#define OMV_CSI_TIM (TIM1)
|
#define OMV_CSI_TIM (TIM1)
|
||||||
#define OMV_CSI_TIM_PIN (&omv_pin_E9_TIM1)
|
#define OMV_CSI_TIM_PIN (&omv_pin_E9_TIM1)
|
||||||
#define OMV_CSI_TIM_CHANNEL (TIM_CHANNEL_1)
|
#define OMV_CSI_TIM_CHANNEL (TIM_CHANNEL_1)
|
||||||
|
|||||||
@ -61,6 +61,10 @@
|
|||||||
#define OMV_CSI_I2C_REINIT (1)
|
#define OMV_CSI_I2C_REINIT (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef OMV_CSI_CLK_TOLERANCE
|
||||||
|
#define OMV_CSI_CLK_TOLERANCE (500000)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __weak
|
#ifndef __weak
|
||||||
#define __weak __attribute__((weak))
|
#define __weak __attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
@ -120,6 +124,7 @@ uint16_t resolution[][2] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static omv_i2c_t csi_i2c;
|
static omv_i2c_t csi_i2c;
|
||||||
|
static omv_clk_t csi_clk;
|
||||||
omv_csi_t csi_all[OMV_CSI_MAX_DEVICES] = {0};
|
omv_csi_t csi_all[OMV_CSI_MAX_DEVICES] = {0};
|
||||||
|
|
||||||
__weak void omv_csi_init0() {
|
__weak void omv_csi_init0() {
|
||||||
@ -178,15 +183,16 @@ __weak int omv_csi_init() {
|
|||||||
|
|
||||||
memset(csi, 0, sizeof(omv_csi_t));
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi->i2c = &csi_i2c;
|
csi->i2c = &csi_i2c;
|
||||||
|
csi->clk = &csi_clk;
|
||||||
csi->fb = framebuffer_get(-1);
|
csi->fb = framebuffer_get(-1);
|
||||||
csi->color_palette = rainbow_table;
|
csi->color_palette = rainbow_table;
|
||||||
omv_csi_ops_init(csi);
|
omv_csi_ops_init(csi);
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the csi external clock (XCLK).
|
// Configure the csi external clock (XCLK).
|
||||||
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
if (omv_csi_set_clk_frequency(csi, OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Detect and initialize sensor(s).
|
// Detect and initialize sensor(s).
|
||||||
for (uint32_t i=0, n_buses=OMV_ARRAY_SIZE(buses); i<n_buses; i++) {
|
for (uint32_t i=0, n_buses=OMV_ARRAY_SIZE(buses); i<n_buses; i++) {
|
||||||
@ -544,10 +550,11 @@ int omv_csi_probe(omv_i2c_t *i2c) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allow reconfiguring (or disabling) the external clock
|
// Sensors can change the clock's frequency or disable it
|
||||||
// if just one sensor is detected, or for main sensors.
|
// (with clk_hz=0). This is allowed only if the clock is
|
||||||
|
// not shared (dev_count == 1) or if this is a main sensor.
|
||||||
if (dev_count == 1 || !csi->auxiliary) {
|
if (dev_count == 1 || !csi->auxiliary) {
|
||||||
omv_csi_set_clk_frequency(csi->clk_hz);
|
omv_csi_set_clk_frequency(csi, csi->clk_hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count aux devices.
|
// Count aux devices.
|
||||||
@ -566,7 +573,7 @@ int omv_csi_probe(omv_i2c_t *i2c) {
|
|||||||
// If more than one aux sensor was detected, the clock
|
// If more than one aux sensor was detected, the clock
|
||||||
// hasn't been changed, so reconfigure using this freq.
|
// hasn't been changed, so reconfigure using this freq.
|
||||||
if (dev_count > 1) {
|
if (dev_count > 1) {
|
||||||
omv_csi_set_clk_frequency(csi->clk_hz);
|
omv_csi_set_clk_frequency(csi, csi->clk_hz);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -605,12 +612,33 @@ __weak int omv_csi_get_id(omv_csi_t *csi) {
|
|||||||
return csi->chip_id;
|
return csi->chip_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
__weak uint32_t omv_csi_get_clk_frequency() {
|
__weak uint32_t omv_csi_get_clk_frequency(omv_csi_t *csi, bool nominal) {
|
||||||
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
omv_clk_t *clk = csi->clk;
|
||||||
|
|
||||||
|
if (clk->get_freq != NULL && !nominal) {
|
||||||
|
// Return the exact frequency
|
||||||
|
return clk->get_freq(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return nominal frequency
|
||||||
|
return clk->freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
__weak int omv_csi_set_clk_frequency(uint32_t frequency) {
|
__weak int omv_csi_set_clk_frequency(omv_csi_t *csi, uint32_t frequency) {
|
||||||
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
omv_clk_t *clk = csi->clk;
|
||||||
|
uint32_t diff_hz = abs(frequency - omv_csi_get_clk_frequency(csi, false));
|
||||||
|
|
||||||
|
if (diff_hz <= OMV_CSI_CLK_TOLERANCE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk->set_freq != NULL &&
|
||||||
|
clk->set_freq(clk, frequency) != 0) {
|
||||||
|
return OMV_CSI_ERROR_CTL_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk->freq = frequency;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__weak bool omv_csi_is_detected(omv_csi_t *csi) {
|
__weak bool omv_csi_is_detected(omv_csi_t *csi) {
|
||||||
|
|||||||
@ -291,6 +291,17 @@ typedef struct _omv_csi_callback_t {
|
|||||||
typedef int (*omv_csi_snapshot_t)
|
typedef int (*omv_csi_snapshot_t)
|
||||||
(omv_csi_t *csi, image_t *image, uint32_t flags);
|
(omv_csi_t *csi, image_t *image, uint32_t flags);
|
||||||
|
|
||||||
|
typedef struct _omv_clk omv_clk_t;
|
||||||
|
|
||||||
|
typedef struct _omv_clk {
|
||||||
|
uint32_t freq;
|
||||||
|
#ifdef OMV_CSI_CLK_PORT_BITS
|
||||||
|
OMV_CSI_CLK_PORT_BITS
|
||||||
|
#endif
|
||||||
|
uint32_t (*get_freq) (omv_clk_t *csi);
|
||||||
|
int (*set_freq) (omv_clk_t *csi, uint32_t freq);
|
||||||
|
} omv_clk_t;
|
||||||
|
|
||||||
typedef struct _omv_csi {
|
typedef struct _omv_csi {
|
||||||
uint32_t chip_id; // Sensor ID 32 bits.
|
uint32_t chip_id; // Sensor ID 32 bits.
|
||||||
uint8_t slv_addr; // Sensor I2C slave address.
|
uint8_t slv_addr; // Sensor I2C slave address.
|
||||||
@ -339,10 +350,11 @@ typedef struct _omv_csi {
|
|||||||
bool auto_rotation; // Rotate Image Automatically
|
bool auto_rotation; // Rotate Image Automatically
|
||||||
bool detected; // Set to true when the sensor is initialized.
|
bool detected; // Set to true when the sensor is initialized.
|
||||||
bool power_on; // Set to true when the sensor is active.
|
bool power_on; // Set to true when the sensor is active.
|
||||||
uint32_t clk_hz; // Clock frequency requested by the driver.
|
|
||||||
|
|
||||||
omv_i2c_t *i2c; // SCCB/I2C bus.
|
omv_i2c_t *i2c; // SCCB/I2C bus.
|
||||||
framebuffer_t *fb; // Frame buffer pointer
|
framebuffer_t *fb; // Frame buffer pointer
|
||||||
|
omv_clk_t *clk; // Clock controller.
|
||||||
|
uint32_t clk_hz; // Clock freqeuency request by this CSI.
|
||||||
|
|
||||||
#ifdef OMV_CSI_PORT_BITS
|
#ifdef OMV_CSI_PORT_BITS
|
||||||
// Additional port-specific members like device base pointer,
|
// Additional port-specific members like device base pointer,
|
||||||
@ -429,10 +441,10 @@ int omv_csi_reset(omv_csi_t *csi, bool hard);
|
|||||||
int omv_csi_get_id(omv_csi_t *csi);
|
int omv_csi_get_id(omv_csi_t *csi);
|
||||||
|
|
||||||
// Returns the xclk freq in hz.
|
// Returns the xclk freq in hz.
|
||||||
uint32_t omv_csi_get_clk_frequency();
|
uint32_t omv_csi_get_clk_frequency(omv_csi_t *csi, bool nominal);
|
||||||
|
|
||||||
// Returns the xclk freq in hz.
|
// Returns the xclk freq in hz.
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency);
|
int omv_csi_set_clk_frequency(omv_csi_t *csi, uint32_t frequency);
|
||||||
|
|
||||||
// Return true if the sensor was detected and initialized.
|
// Return true if the sensor was detected and initialized.
|
||||||
bool omv_csi_is_detected(omv_csi_t *csi);
|
bool omv_csi_is_detected(omv_csi_t *csi);
|
||||||
|
|||||||
@ -70,7 +70,8 @@
|
|||||||
#define EVENT_THRESHOLD_SIGMA 10
|
#define EVENT_THRESHOLD_SIGMA 10
|
||||||
|
|
||||||
#define EVT_CLK_MULTIPLIER (2)
|
#define EVT_CLK_MULTIPLIER (2)
|
||||||
#define EVT_CLK_FREQ (((omv_csi_get_clk_frequency() * EVT_CLK_MULTIPLIER) + 500000) / 1000000)
|
#define EVT_CLK_FREQ \
|
||||||
|
(((omv_csi_get_clk_frequency(csi, false) * EVT_CLK_MULTIPLIER) + 500000) / 1000000)
|
||||||
|
|
||||||
#define AFK_50_HZ (50)
|
#define AFK_50_HZ (50)
|
||||||
#define AFK_60_HZ (60)
|
#define AFK_60_HZ (60)
|
||||||
@ -235,7 +236,7 @@ static int set_framerate(omv_csi_t *csi, int framerate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lines = ACTIVE_SENSOR_HEIGHT + VSYNC_CLOCK_CYCLES;
|
int lines = ACTIVE_SENSOR_HEIGHT + VSYNC_CLOCK_CYCLES;
|
||||||
int clocks_per_frame = (omv_csi_get_clk_frequency() * EVT_CLK_MULTIPLIER) / framerate;
|
int clocks_per_frame = (omv_csi_get_clk_frequency(csi, false) * EVT_CLK_MULTIPLIER) / framerate;
|
||||||
int hsync_clocks = (clocks_per_frame / lines) - ACTIVE_SENSOR_WIDTH;
|
int hsync_clocks = (clocks_per_frame / lines) - ACTIVE_SENSOR_WIDTH;
|
||||||
|
|
||||||
if (hsync_clocks <= 0) {
|
if (hsync_clocks <= 0) {
|
||||||
|
|||||||
@ -476,7 +476,7 @@ static int reset(omv_csi_t *csi) {
|
|||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, 0x301A, reg | (1 << 9));
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, 0x301A, reg | (1 << 9));
|
||||||
|
|
||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_SYSCTL_PLL_DIVIDER_M_N,
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_CAM_SYSCTL_PLL_DIVIDER_M_N,
|
||||||
(omv_csi_get_clk_frequency() == OMV_MT9M114_CLK_FREQ)
|
(omv_csi_get_clk_frequency(csi, true) == OMV_MT9M114_CLK_FREQ)
|
||||||
? 0x120 // xclk=24MHz, m=32, n=1, csi=48MHz, bus=76.8MHz
|
? 0x120 // xclk=24MHz, m=32, n=1, csi=48MHz, bus=76.8MHz
|
||||||
: 0x448); // xclk=25MHz, m=72, n=4, csi=45MHz, bus=72MHz
|
: 0x448); // xclk=25MHz, m=72, n=4, csi=45MHz, bus=72MHz
|
||||||
|
|
||||||
@ -675,7 +675,7 @@ static int set_framesize(omv_csi_t *csi, omv_csi_framesize_t framesize) {
|
|||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_Y_ADDR_END, sensor_he);
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_Y_ADDR_END, sensor_he);
|
||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_X_ADDR_END, sensor_we);
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_X_ADDR_END, sensor_we);
|
||||||
|
|
||||||
int pixclk = (omv_csi_get_clk_frequency() == OMV_MT9M114_CLK_FREQ) ? 48000000 : 45000000;
|
int pixclk = (omv_csi_get_clk_frequency(csi, true) == OMV_MT9M114_CLK_FREQ) ? 48000000 : 45000000;
|
||||||
|
|
||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK, pixclk >> 16);
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK, pixclk >> 16);
|
||||||
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK + 2, pixclk);
|
ret |= omv_i2c_writew2(csi->i2c, csi->slv_addr, MT9M114_REG_SENSOR_CFG_PIXCLK + 2, pixclk);
|
||||||
|
|||||||
@ -342,7 +342,7 @@ static int set_auto_exposure(omv_csi_t *csi, int enable, int exposure_us) {
|
|||||||
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, window_width, &row_time_0);
|
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, window_width, &row_time_0);
|
||||||
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, horizontal_blanking, &row_time_1);
|
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, horizontal_blanking, &row_time_1);
|
||||||
|
|
||||||
int clock = omv_csi_get_clk_frequency();
|
int clock = omv_csi_get_clk_frequency(csi, false);
|
||||||
|
|
||||||
int exposure = IM_MIN(exposure_us, MICROSECOND_CLKS / 2) * (clock / MICROSECOND_CLKS);
|
int exposure = IM_MIN(exposure_us, MICROSECOND_CLKS / 2) * (clock / MICROSECOND_CLKS);
|
||||||
int row_time = row_time_0 + row_time_1;
|
int row_time = row_time_0 + row_time_1;
|
||||||
@ -388,7 +388,7 @@ static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
|
|||||||
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, fine_shutter_width_total, &int_pixels);
|
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, fine_shutter_width_total, &int_pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clock = omv_csi_get_clk_frequency();
|
int clock = omv_csi_get_clk_frequency(csi, false);
|
||||||
|
|
||||||
if (reg & (context ? MT9V0X4_AEC_ENABLE_B : MT9V0XX_AEC_ENABLE)) {
|
if (reg & (context ? MT9V0X4_AEC_ENABLE_B : MT9V0XX_AEC_ENABLE)) {
|
||||||
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, MT9V0XX_AEC_EXPOSURE_OUTPUT, &int_rows);
|
ret |= omv_i2c_readw(csi->i2c, csi->slv_addr, MT9V0XX_AEC_EXPOSURE_OUTPUT, &int_rows);
|
||||||
|
|||||||
@ -1120,12 +1120,13 @@ static int get_gain_db(omv_csi_t *csi, float *gain_db) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calc_pclk_freq(uint8_t sc_pll_ctrl_0,
|
static int calc_pclk_freq(omv_csi_t *csi,
|
||||||
|
uint8_t sc_pll_ctrl_0,
|
||||||
uint8_t sc_pll_ctrl_1,
|
uint8_t sc_pll_ctrl_1,
|
||||||
uint8_t sc_pll_ctrl_2,
|
uint8_t sc_pll_ctrl_2,
|
||||||
uint8_t sc_pll_ctrl_3,
|
uint8_t sc_pll_ctrl_3,
|
||||||
uint8_t sys_root_div) {
|
uint8_t sys_root_div) {
|
||||||
uint32_t pclk_freq = omv_csi_get_clk_frequency();
|
uint32_t pclk_freq = omv_csi_get_clk_frequency(csi, false);
|
||||||
pclk_freq /= ((sc_pll_ctrl_3 & 0x10) != 0x00) ? 2 : 1;
|
pclk_freq /= ((sc_pll_ctrl_3 & 0x10) != 0x00) ? 2 : 1;
|
||||||
pclk_freq /= ((sc_pll_ctrl_0 & 0x0F) == 0x0A) ? 5 : 4; //camera has two MIPI lanes
|
pclk_freq /= ((sc_pll_ctrl_0 & 0x0F) == 0x0A) ? 5 : 4; //camera has two MIPI lanes
|
||||||
switch (sc_pll_ctrl_3 & 0x0F) {
|
switch (sc_pll_ctrl_3 & 0x0F) {
|
||||||
@ -1171,7 +1172,7 @@ static int set_auto_exposure(omv_csi_t *csi, int enable, int exposure_us) {
|
|||||||
uint16_t hts = (hts_h << 8) | hts_l;
|
uint16_t hts = (hts_h << 8) | hts_l;
|
||||||
uint16_t vts = (vts_h << 8) | vts_l;
|
uint16_t vts = (vts_h << 8) | vts_l;
|
||||||
|
|
||||||
int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv);
|
int pclk_freq = calc_pclk_freq(csi, spc0, spc1, spc2, spc3, sysrootdiv);
|
||||||
int clocks_per_us = pclk_freq / 1000000;
|
int clocks_per_us = pclk_freq / 1000000;
|
||||||
int exposure = __USAT((exposure_us * clocks_per_us) / hts, 16);
|
int exposure = __USAT((exposure_us * clocks_per_us) / hts, 16);
|
||||||
|
|
||||||
@ -1214,7 +1215,7 @@ static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
|
|||||||
|
|
||||||
aec = IM_MIN(aec, vts);
|
aec = IM_MIN(aec, vts);
|
||||||
|
|
||||||
int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv);
|
int pclk_freq = calc_pclk_freq(csi, spc0, spc1, spc2, spc3, sysrootdiv);
|
||||||
int clocks_per_us = pclk_freq / 1000000;
|
int clocks_per_us = pclk_freq / 1000000;
|
||||||
*exposure_us = (aec * hts) / clocks_per_us;
|
*exposure_us = (aec * hts) / clocks_per_us;
|
||||||
|
|
||||||
|
|||||||
@ -182,7 +182,17 @@ int alif_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
static uint32_t alif_clk_get_frequency(omv_clk_t *clk) {
|
||||||
|
uint32_t div = (CLKCTL_PER_MST->CAMERA_PIXCLK_CTRL & CAMERA_PIXCLK_CTRL_DIVISOR_Msk) >>
|
||||||
|
CAMERA_PIXCLK_CTRL_DIVISOR_Pos;
|
||||||
|
if (CLKCTL_PER_MST->CAMERA_PIXCLK_CTRL & CAMERA_PIXCLK_CTRL_CLK_SEL) {
|
||||||
|
return 480000000 / div;
|
||||||
|
} else {
|
||||||
|
return 400000000 / div;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alif_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||||
// Configure CPI clock source (400MHz or 480MHz) and divider.
|
// Configure CPI clock source (400MHz or 480MHz) and divider.
|
||||||
if (frequency >= 24000000) {
|
if (frequency >= 24000000) {
|
||||||
set_cpi_pixel_clk(CPI_PIX_CLKSEL_480MZ, 20);
|
set_cpi_pixel_clk(CPI_PIX_CLKSEL_480MZ, 20);
|
||||||
@ -196,16 +206,6 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
|
||||||
uint32_t div = (CLKCTL_PER_MST->CAMERA_PIXCLK_CTRL & CAMERA_PIXCLK_CTRL_DIVISOR_Msk) >>
|
|
||||||
CAMERA_PIXCLK_CTRL_DIVISOR_Pos;
|
|
||||||
if (CLKCTL_PER_MST->CAMERA_PIXCLK_CTRL & CAMERA_PIXCLK_CTRL_CLK_SEL) {
|
|
||||||
return 480000000 / div;
|
|
||||||
} else {
|
|
||||||
return 400000000 / div;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t omv_csi_get_fb_offset(omv_csi_t *csi) {
|
static uint32_t omv_csi_get_fb_offset(omv_csi_t *csi) {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
@ -425,10 +425,18 @@ int alif_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||||
|
// Set CPI base (LP/CPI).
|
||||||
csi->base = OMV_CSI_BASE;
|
csi->base = OMV_CSI_BASE;
|
||||||
|
|
||||||
|
// Set CSI ops.
|
||||||
csi->abort = alif_csi_abort;
|
csi->abort = alif_csi_abort;
|
||||||
csi->config = alif_csi_config;
|
csi->config = alif_csi_config;
|
||||||
csi->snapshot = alif_csi_snapshot;
|
csi->snapshot = alif_csi_snapshot;
|
||||||
|
|
||||||
|
// Set CSI clock ops.
|
||||||
|
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||||
|
csi->clk->set_freq = alif_clk_set_frequency;
|
||||||
|
csi->clk->get_freq = alif_clk_get_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_CSI
|
#endif // MICROPY_PY_CSI
|
||||||
|
|||||||
@ -104,11 +104,11 @@ static int imx_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
static uint32_t imx_clk_get_frequency(omv_clk_t *clk) {
|
||||||
return 24000000 / (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1);
|
return 24000000 / (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
static int imx_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||||
if (frequency >= 24000000) {
|
if (frequency >= 24000000) {
|
||||||
CLOCK_SetDiv(kCLOCK_CsiDiv, 0);
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 0);
|
||||||
} else if (frequency >= 12000000) {
|
} else if (frequency >= 12000000) {
|
||||||
@ -504,9 +504,15 @@ int imx_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||||
|
// Set CSI ops.
|
||||||
csi->abort = imx_csi_abort;
|
csi->abort = imx_csi_abort;
|
||||||
csi->config = imx_csi_config;
|
csi->config = imx_csi_config;
|
||||||
csi->snapshot = imx_csi_snapshot;
|
csi->snapshot = imx_csi_snapshot;
|
||||||
|
|
||||||
|
// Set CSI clock ops.
|
||||||
|
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||||
|
csi->clk->set_freq = imx_clk_set_frequency;
|
||||||
|
csi->clk->get_freq = imx_clk_get_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_CSI
|
#endif // MICROPY_PY_CSI
|
||||||
|
|||||||
@ -94,11 +94,11 @@ static int nrf_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
static uint32_t nrf_clk_get_frequency(omv_clk_t *clk) {
|
||||||
return OMV_CSI_CLK_FREQUENCY;
|
return OMV_CSI_CLK_FREQUENCY;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
static int nrf_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||||
nrf_gpio_cfg_output(OMV_CSI_MXCLK_PIN);
|
nrf_gpio_cfg_output(OMV_CSI_MXCLK_PIN);
|
||||||
|
|
||||||
// Generates 16 MHz signal using I2S peripheral
|
// Generates 16 MHz signal using I2S peripheral
|
||||||
@ -207,7 +207,14 @@ static int nrf_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||||
|
// Set CSI ops.
|
||||||
csi->config = nrf_csi_config;
|
csi->config = nrf_csi_config;
|
||||||
csi->snapshot = nrf_csi_snapshot;
|
csi->snapshot = nrf_csi_snapshot;
|
||||||
|
|
||||||
|
|
||||||
|
// Set CSI clock ops.
|
||||||
|
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||||
|
csi->clk->set_freq = nrf_clk_set_frequency;
|
||||||
|
csi->clk->get_freq = nrf_clk_get_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,7 +119,11 @@ static int rp2_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
static uint32_t rp2_clk_get_frequency(omv_clk_t *clk) {
|
||||||
|
return OMV_CSI_CLK_FREQUENCY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rp2_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||||
uint32_t p = 4;
|
uint32_t p = 4;
|
||||||
|
|
||||||
// Allocate pin to the PWM
|
// Allocate pin to the PWM
|
||||||
@ -226,9 +230,15 @@ static int rp2_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||||
|
// Set CSI ops.
|
||||||
csi->abort = rp2_csi_abort;
|
csi->abort = rp2_csi_abort;
|
||||||
csi->config = rp2_csi_config;
|
csi->config = rp2_csi_config;
|
||||||
csi->snapshot = rp2_csi_snapshot;
|
csi->snapshot = rp2_csi_snapshot;
|
||||||
|
|
||||||
|
// Set CSI clock ops.
|
||||||
|
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||||
|
csi->clk->set_freq = rp2_clk_set_frequency;
|
||||||
|
csi->clk->get_freq = rp2_clk_get_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_CSI
|
#endif // MICROPY_PY_CSI
|
||||||
|
|||||||
@ -381,30 +381,25 @@ static int stm_csi_shutdown(omv_csi_t *csi, int enable) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
static uint32_t stm_clk_get_frequency(omv_clk_t *clk) {
|
||||||
omv_csi_t *csi = omv_csi_get(-1);
|
if (!clk->tim.Instance) {
|
||||||
|
|
||||||
if (!csi->tim.Instance) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (OMV_CSI_TIM_PCLK_FREQ() * 2) / (csi->tim.Init.Period + 1);
|
return (OMV_CSI_TIM_PCLK_FREQ() * 2) / (clk->tim.Init.Period + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO save frequency.
|
static int stm_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|
||||||
#if (OMV_CSI_CLK_SOURCE == OMV_CSI_CLK_SOURCE_TIM)
|
#if (OMV_CSI_CLK_SOURCE == OMV_CSI_CLK_SOURCE_TIM)
|
||||||
omv_csi_t *csi = omv_csi_get(-1);
|
|
||||||
|
|
||||||
if (frequency == 0) {
|
if (frequency == 0) {
|
||||||
if (csi->tim.Init.Period) {
|
if (clk->tim.Init.Period) {
|
||||||
HAL_TIM_PWM_Stop(&csi->tim, OMV_CSI_TIM_CHANNEL);
|
HAL_TIM_PWM_Stop(&clk->tim, OMV_CSI_TIM_CHANNEL);
|
||||||
HAL_TIM_PWM_DeInit(&csi->tim);
|
HAL_TIM_PWM_DeInit(&clk->tim);
|
||||||
memset(&csi->tim, 0, sizeof(csi->tim));
|
memset(&clk->tim, 0, sizeof(clk->tim));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
csi->tim.Instance = OMV_CSI_TIM;
|
clk->tim.Instance = OMV_CSI_TIM;
|
||||||
|
|
||||||
// TCLK (PCLK * 2)
|
// TCLK (PCLK * 2)
|
||||||
int tclk = OMV_CSI_TIM_PCLK_FREQ() * 2;
|
int tclk = OMV_CSI_TIM_PCLK_FREQ() * 2;
|
||||||
@ -413,20 +408,20 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
int period = fast_ceilf(tclk / ((float) frequency)) - 1;
|
int period = fast_ceilf(tclk / ((float) frequency)) - 1;
|
||||||
int pulse = (period + 1) / 2;
|
int pulse = (period + 1) / 2;
|
||||||
|
|
||||||
if (csi->tim.Init.Period && (csi->tim.Init.Period != period)) {
|
if (clk->tim.Init.Period && (clk->tim.Init.Period != period)) {
|
||||||
// __HAL_TIM_SET_AUTORELOAD sets csi->tim.Init.Period...
|
// __HAL_TIM_SET_AUTORELOAD sets clk->tim.Init.Period...
|
||||||
__HAL_TIM_SET_AUTORELOAD(&csi->tim, period);
|
__HAL_TIM_SET_AUTORELOAD(&clk->tim, period);
|
||||||
__HAL_TIM_SET_COMPARE(&csi->tim, OMV_CSI_TIM_CHANNEL, pulse);
|
__HAL_TIM_SET_COMPARE(&clk->tim, OMV_CSI_TIM_CHANNEL, pulse);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Timer base configuration */
|
/* Timer base configuration */
|
||||||
csi->tim.Init.Period = period;
|
clk->tim.Init.Period = period;
|
||||||
csi->tim.Init.Prescaler = 0;
|
clk->tim.Init.Prescaler = 0;
|
||||||
csi->tim.Init.CounterMode = TIM_COUNTERMODE_UP;
|
clk->tim.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
csi->tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
clk->tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
csi->tim.Init.RepetitionCounter = 0;
|
clk->tim.Init.RepetitionCounter = 0;
|
||||||
csi->tim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
clk->tim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||||
|
|
||||||
/* Timer channel configuration */
|
/* Timer channel configuration */
|
||||||
TIM_OC_InitTypeDef TIMOCHandle;
|
TIM_OC_InitTypeDef TIMOCHandle;
|
||||||
@ -438,9 +433,9 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
TIMOCHandle.OCIdleState = TIM_OCIDLESTATE_RESET;
|
TIMOCHandle.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||||
TIMOCHandle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
TIMOCHandle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||||
|
|
||||||
if ((HAL_TIM_PWM_Init(&csi->tim) != HAL_OK)
|
if ((HAL_TIM_PWM_Init(&clk->tim) != HAL_OK)
|
||||||
|| (HAL_TIM_PWM_ConfigChannel(&csi->tim, &TIMOCHandle, OMV_CSI_TIM_CHANNEL) != HAL_OK)
|
|| (HAL_TIM_PWM_ConfigChannel(&clk->tim, &TIMOCHandle, OMV_CSI_TIM_CHANNEL) != HAL_OK)
|
||||||
|| (HAL_TIM_PWM_Start(&csi->tim, OMV_CSI_TIM_CHANNEL) != HAL_OK)) {
|
|| (HAL_TIM_PWM_Start(&clk->tim, OMV_CSI_TIM_CHANNEL) != HAL_OK)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#elif (OMV_CSI_CLK_SOURCE == OMV_CSI_CLK_SOURCE_MCO)
|
#elif (OMV_CSI_CLK_SOURCE == OMV_CSI_CLK_SOURCE_MCO)
|
||||||
@ -1068,9 +1063,15 @@ static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||||
|
// Set CSI ops.
|
||||||
csi->abort = stm_csi_abort;
|
csi->abort = stm_csi_abort;
|
||||||
csi->config = stm_csi_config;
|
csi->config = stm_csi_config;
|
||||||
csi->shutdown = stm_csi_shutdown;
|
csi->shutdown = stm_csi_shutdown;
|
||||||
csi->snapshot = stm_csi_snapshot;
|
csi->snapshot = stm_csi_snapshot;
|
||||||
|
|
||||||
|
// Set CSI clock ops.
|
||||||
|
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||||
|
csi->clk->set_freq = stm_clk_set_frequency;
|
||||||
|
csi->clk->get_freq = stm_clk_get_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,19 +137,24 @@ typedef I2C_HandleTypeDef *omv_i2c_dev_t;
|
|||||||
#define OMV_CSI_PORT_BITS_MDMA
|
#define OMV_CSI_PORT_BITS_MDMA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(STM32N6)
|
#if defined(STM32N6)
|
||||||
#define OMV_CSI_PORT_BITS \
|
#define OMV_CSI_PORT_BITS \
|
||||||
struct { \
|
struct { \
|
||||||
TIM_HandleTypeDef tim; \
|
|
||||||
DCMIPP_HandleTypeDef dcmi; \
|
DCMIPP_HandleTypeDef dcmi; \
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
#define OMV_CSI_PORT_BITS \
|
#define OMV_CSI_PORT_BITS \
|
||||||
struct { \
|
struct { \
|
||||||
TIM_HandleTypeDef tim; \
|
|
||||||
DMA_HandleTypeDef dma; \
|
DMA_HandleTypeDef dma; \
|
||||||
DCMI_HandleTypeDef dcmi; \
|
DCMI_HandleTypeDef dcmi; \
|
||||||
OMV_CSI_PORT_BITS_MDMA \
|
OMV_CSI_PORT_BITS_MDMA \
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define OMV_CSI_CLK_PORT_BITS \
|
||||||
|
struct { \
|
||||||
|
TIM_HandleTypeDef tim; \
|
||||||
|
};
|
||||||
|
|
||||||
#endif // __OMV_PORTCONFIG_H__
|
#endif // __OMV_PORTCONFIG_H__
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user