mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
Merge pull request #2691 from openmv/n6_port_dual_csi
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
ports/all: Dual CSI support.
This commit is contained in:
commit
190aecc45c
5
Makefile
5
Makefile
@ -138,6 +138,11 @@ MPY_CFLAGS += -DMICROPY_PY_CSI=1
|
|||||||
MPY_MKARGS += MICROPY_PY_CSI=1
|
MPY_MKARGS += MICROPY_PY_CSI=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_CSI_NG), 1)
|
||||||
|
MPY_CFLAGS += -DMICROPY_PY_CSI_NG=1
|
||||||
|
MPY_MKARGS += MICROPY_PY_CSI_NG=1
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(MICROPY_PY_FIR), 1)
|
ifeq ($(MICROPY_PY_FIR), 1)
|
||||||
MPY_CFLAGS += -DMICROPY_PY_FIR=1
|
MPY_CFLAGS += -DMICROPY_PY_FIR=1
|
||||||
MPY_MKARGS += MICROPY_PY_FIR=1
|
MPY_MKARGS += MICROPY_PY_FIR=1
|
||||||
|
@ -15,6 +15,7 @@ OMV_BOARD_CFLAGS = -DCORE_CM7 \
|
|||||||
OMV_ENABLE_BL=0
|
OMV_ENABLE_BL=0
|
||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_LWIP = 1
|
MICROPY_PY_LWIP = 1
|
||||||
|
@ -14,6 +14,7 @@ OMV_BOARD_CFLAGS = -DNRF52_SERIES \
|
|||||||
-DCONFIG_GPIO_AS_PINRESET
|
-DCONFIG_GPIO_AS_PINRESET
|
||||||
DFU_DEVICE=0x0483:0xdf11
|
DFU_DEVICE=0x0483:0xdf11
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB=1
|
MICROPY_PY_ULAB=1
|
||||||
MICROPY_PY_AUDIO=1
|
MICROPY_PY_AUDIO=1
|
||||||
|
@ -73,7 +73,7 @@ PIXEL_LOOP:
|
|||||||
.wrap
|
.wrap
|
||||||
|
|
||||||
% c-sdk {
|
% c-sdk {
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
int omv_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
uint offset;
|
uint offset;
|
||||||
pio_sm_config config;
|
pio_sm_config config;
|
||||||
@ -86,7 +86,7 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 7, false);
|
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 7, false);
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
||||||
config = dcmi_odd_byte_program_get_default_config(offset);
|
config = dcmi_odd_byte_program_get_default_config(offset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
set(MICROPY_PY_CSI 1)
|
set(MICROPY_PY_CSI 1)
|
||||||
|
set(MICROPY_PY_CSI_NG 1)
|
||||||
set(MICROPY_PY_FIR 1)
|
set(MICROPY_PY_FIR 1)
|
||||||
set(MICROPY_PY_ULAB 1)
|
set(MICROPY_PY_ULAB 1)
|
||||||
set(MICROPY_PY_NINAW10 1)
|
set(MICROPY_PY_NINAW10 1)
|
||||||
|
@ -17,6 +17,7 @@ OMV_ENABLE_BL = 0
|
|||||||
OMV_ENABLE_UVC = 1
|
OMV_ENABLE_UVC = 1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 0
|
MICROPY_PY_WINC1500 = 0
|
||||||
|
@ -16,6 +16,7 @@ OMV_ENABLE_BL=0
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 0
|
MICROPY_PY_WINC1500 = 0
|
||||||
|
@ -11,5 +11,6 @@ OMV_ENABLE_BL=1
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_BOARD_CFLAGS=-DUSE_USB_FS
|
OMV_BOARD_CFLAGS=-DUSE_USB_FS
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
$(error "This camera is no longer supported :O Have fun hacking the code $(BRACKET)")
|
$(error "This camera is no longer supported :O Have fun hacking the code $(BRACKET)")
|
||||||
|
@ -11,6 +11,7 @@ OMV_ENABLE_BL=1
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
MICROPY_PY_DISPLAY = 1
|
MICROPY_PY_DISPLAY = 1
|
||||||
|
@ -11,6 +11,7 @@ OMV_ENABLE_BL=1
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
|
@ -12,6 +12,7 @@ OMV_ENABLE_BL=1
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
|
@ -13,6 +13,7 @@ OMV_ENABLE_UVC=1
|
|||||||
OMV_GENX320_ENABLE=1
|
OMV_GENX320_ENABLE=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
|
@ -12,6 +12,7 @@ OMV_ENABLE_BL=1
|
|||||||
OMV_ENABLE_UVC=1
|
OMV_ENABLE_UVC=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_WINC1500 = 1
|
MICROPY_PY_WINC1500 = 1
|
||||||
|
@ -249,6 +249,7 @@ extern unsigned char OMV_BOARD_UID_ADDR[12]; // Unique address.
|
|||||||
// CSI I2C bus
|
// CSI I2C bus
|
||||||
#define OMV_CSI_I2C_ID (0)
|
#define OMV_CSI_I2C_ID (0)
|
||||||
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_FULL)
|
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_FULL)
|
||||||
|
#define OMV_CSI_I2C_REINIT (0)
|
||||||
|
|
||||||
// FIR I2C bus
|
// FIR I2C bus
|
||||||
#define OMV_FIR_I2C_ID (1)
|
#define OMV_FIR_I2C_ID (1)
|
||||||
|
@ -14,6 +14,7 @@ OMV_HSE_VALUE=12000000
|
|||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
OMV_TOF_VL53L8CX_ENABLE=1
|
OMV_TOF_VL53L8CX_ENABLE=1
|
||||||
MICROPY_PY_CSI = $(CORE_M55_HP)
|
MICROPY_PY_CSI = $(CORE_M55_HP)
|
||||||
|
MICROPY_PY_CSI_NG = $(CORE_M55_HP)
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_TOF = 1
|
MICROPY_PY_TOF = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#define OMV_LEPTON_ENABLE (1)
|
#define OMV_LEPTON_ENABLE (1)
|
||||||
#define OMV_PAG7936_ENABLE (1)
|
#define OMV_PAG7936_ENABLE (1)
|
||||||
#define OMV_PAG7936_MIPI_CSI2 (1)
|
#define OMV_PAG7936_MIPI_CSI2 (1)
|
||||||
|
#define OMV_SOFTCSI_ENABLE (0)
|
||||||
#define OMV_PS5520_ENABLE (1)
|
#define OMV_PS5520_ENABLE (1)
|
||||||
#define OMV_GENX320_EHC_ENABLE (1)
|
#define OMV_GENX320_EHC_ENABLE (1)
|
||||||
#define OMV_GENX320_HSYNC_VALUE (0x1)
|
#define OMV_GENX320_HSYNC_VALUE (0x1)
|
||||||
@ -279,6 +280,7 @@
|
|||||||
#define OMV_CSI_DMA_REQUEST (HPDMA1_REQUEST_DCMI_PSSI)
|
#define OMV_CSI_DMA_REQUEST (HPDMA1_REQUEST_DCMI_PSSI)
|
||||||
#define OMV_CSI_DMA_MEMCPY_ENABLE (0)
|
#define OMV_CSI_DMA_MEMCPY_ENABLE (0)
|
||||||
#define OMV_CSI_HW_CROP_ENABLE (1)
|
#define OMV_CSI_HW_CROP_ENABLE (1)
|
||||||
|
#define OMV_CSI_MAX_DEVICES (3)
|
||||||
|
|
||||||
#define OMV_CSI_D0_PIN (&omv_pin_A1_DCMI)
|
#define OMV_CSI_D0_PIN (&omv_pin_A1_DCMI)
|
||||||
#define OMV_CSI_D1_PIN (&omv_pin_A10_DCMI)
|
#define OMV_CSI_D1_PIN (&omv_pin_A10_DCMI)
|
||||||
|
@ -27,6 +27,7 @@ OMV_BOSON_ENABLE=1
|
|||||||
OMV_GENX320_ENABLE=1
|
OMV_GENX320_ENABLE=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_IMU = 1
|
MICROPY_PY_IMU = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
|
@ -202,6 +202,7 @@
|
|||||||
#define OMV_CSI_DMA_MEMCPY_ENABLE (1)
|
#define OMV_CSI_DMA_MEMCPY_ENABLE (1)
|
||||||
#define OMV_CSI_HW_SWAP_ENABLE (1)
|
#define OMV_CSI_HW_SWAP_ENABLE (1)
|
||||||
#define OMV_CSI_HW_CROP_ENABLE (1)
|
#define OMV_CSI_HW_CROP_ENABLE (1)
|
||||||
|
#define OMV_CSI_MAX_DEVICES (2)
|
||||||
|
|
||||||
#define OMV_CSI_D0_PIN (&omv_pin_DCMI_D0)
|
#define OMV_CSI_D0_PIN (&omv_pin_DCMI_D0)
|
||||||
#define OMV_CSI_D1_PIN (&omv_pin_DCMI_D1)
|
#define OMV_CSI_D1_PIN (&omv_pin_DCMI_D1)
|
||||||
|
@ -12,6 +12,7 @@ OMV_BOSON_ENABLE=1
|
|||||||
OMV_GENX320_ENABLE=1
|
OMV_GENX320_ENABLE=1
|
||||||
OMV_LEPTON_SDK_ENABLE=1
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
MICROPY_PY_CSI = 1
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_CSI_NG = 1
|
||||||
MICROPY_PY_FIR = 1
|
MICROPY_PY_FIR = 1
|
||||||
MICROPY_PY_ULAB = 1
|
MICROPY_PY_ULAB = 1
|
||||||
MICROPY_PY_LWIP = 1
|
MICROPY_PY_LWIP = 1
|
||||||
|
@ -57,7 +57,7 @@ PIXEL_LOOP:
|
|||||||
.wrap
|
.wrap
|
||||||
|
|
||||||
% c-sdk {
|
% c-sdk {
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
int omv_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
uint offset;
|
uint offset;
|
||||||
pio_sm_config config;
|
pio_sm_config config;
|
||||||
@ -70,7 +70,7 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 8, false);
|
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 8, false);
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
||||||
config = dcmi_odd_byte_program_get_default_config(offset);
|
config = dcmi_odd_byte_program_get_default_config(offset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
set(MICROPY_PY_CSI 1)
|
set(MICROPY_PY_CSI 1)
|
||||||
|
set(MICROPY_PY_CSI_NG 1)
|
||||||
set(MICROPY_PY_FIR 1)
|
set(MICROPY_PY_FIR 1)
|
||||||
set(MICROPY_PY_ULAB 1)
|
set(MICROPY_PY_ULAB 1)
|
||||||
set(MICROPY_PY_NINAW10 0)
|
set(MICROPY_PY_NINAW10 0)
|
||||||
|
1272
common/omv_csi.c
1272
common/omv_csi.c
File diff suppressed because it is too large
Load Diff
151
common/omv_csi.h
151
common/omv_csi.h
@ -50,7 +50,7 @@
|
|||||||
#define FROGEYE2020_SLV_ADDR (0x6E)
|
#define FROGEYE2020_SLV_ADDR (0x6E)
|
||||||
#define PAG7920_SLV_ADDR (0x80)
|
#define PAG7920_SLV_ADDR (0x80)
|
||||||
#define PAG7936_SLV_ADDR (0x80)
|
#define PAG7936_SLV_ADDR (0x80)
|
||||||
#define SOFTCSI_SLV_ADDR (0x7f)
|
#define PAG7936_SLV_ADDR_ALT (0x2A)
|
||||||
#define PS5520_SLV_ADDR (0x90)
|
#define PS5520_SLV_ADDR (0x90)
|
||||||
|
|
||||||
// Chip ID Registers
|
// Chip ID Registers
|
||||||
@ -104,6 +104,10 @@
|
|||||||
#define OMV_CSI_CLK_SOURCE_TIM (1U)
|
#define OMV_CSI_CLK_SOURCE_TIM (1U)
|
||||||
#define OMV_CSI_CLK_SOURCE_OSC (2U)
|
#define OMV_CSI_CLK_SOURCE_OSC (2U)
|
||||||
|
|
||||||
|
#ifndef OMV_CSI_MAX_DEVICES
|
||||||
|
#define OMV_CSI_MAX_DEVICES (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OMV_CSI_ACTIVE_LOW = 0,
|
OMV_CSI_ACTIVE_LOW = 0,
|
||||||
OMV_CSI_ACTIVE_HIGH = 1
|
OMV_CSI_ACTIVE_HIGH = 1
|
||||||
@ -189,6 +193,11 @@ typedef enum {
|
|||||||
OMV_CSI_IOCTL_FLAGS_ABORT = (1 << 8),
|
OMV_CSI_IOCTL_FLAGS_ABORT = (1 << 8),
|
||||||
} omv_csi_ioctl_flags_t;
|
} omv_csi_ioctl_flags_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OMV_CSI_CAPTURE_FLAGS_UPDATE = (1 << 0),
|
||||||
|
OMV_CSI_CAPTURE_FLAGS_NBLOCK = (1 << 1),
|
||||||
|
} omv_csi_capture_flags_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OMV_CSI_IOCTL_SET_READOUT_WINDOW = 0x00 | OMV_CSI_IOCTL_FLAGS_ABORT,
|
OMV_CSI_IOCTL_SET_READOUT_WINDOW = 0x00 | OMV_CSI_IOCTL_FLAGS_ABORT,
|
||||||
OMV_CSI_IOCTL_GET_READOUT_WINDOW = 0x01,
|
OMV_CSI_IOCTL_GET_READOUT_WINDOW = 0x01,
|
||||||
@ -250,6 +259,7 @@ typedef enum {
|
|||||||
OMV_CSI_ERROR_FRAMEBUFFER_ERROR = -18,
|
OMV_CSI_ERROR_FRAMEBUFFER_ERROR = -18,
|
||||||
OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW = -19,
|
OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW = -19,
|
||||||
OMV_CSI_ERROR_JPEG_OVERFLOW = -20,
|
OMV_CSI_ERROR_JPEG_OVERFLOW = -20,
|
||||||
|
OMV_CSI_ERROR_WOULD_BLOCK = -21,
|
||||||
} omv_csi_error_t;
|
} omv_csi_error_t;
|
||||||
|
|
||||||
#if (OMV_GENX320_ENABLE == 1)
|
#if (OMV_GENX320_ENABLE == 1)
|
||||||
@ -270,10 +280,13 @@ typedef enum {
|
|||||||
} omv_csi_genx320_bias_t;
|
} omv_csi_genx320_bias_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*vsync_cb_t) (uint32_t vsync);
|
|
||||||
typedef void (*frame_cb_t) ();
|
|
||||||
typedef struct _omv_csi omv_csi_t;
|
typedef struct _omv_csi omv_csi_t;
|
||||||
|
|
||||||
|
typedef struct _omv_csi_callback_t {
|
||||||
|
void (*fun) (void *);
|
||||||
|
void *arg;
|
||||||
|
} omv_csi_cb_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.
|
||||||
@ -296,14 +309,15 @@ typedef struct _omv_csi {
|
|||||||
uint32_t cfa_format : 3; // CFA format/pattern.
|
uint32_t cfa_format : 3; // CFA format/pattern.
|
||||||
uint32_t mipi_if : 1; // CSI-2 interface.
|
uint32_t mipi_if : 1; // CSI-2 interface.
|
||||||
uint32_t mipi_brate : 12; // CSI-2 interface bitrate.
|
uint32_t mipi_brate : 12; // CSI-2 interface bitrate.
|
||||||
|
uint32_t auxiliary : 1; // Indicates that the sensor can be used in dual-CSI config.
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint16_t *color_palette; // Color palette used for color lookup.
|
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_delays; // Set to true to disable all sensor settling time delays.
|
||||||
bool disable_full_flush; // Turn off default frame buffer flush policy when full.
|
bool disable_full_flush; // Turn off default frame buffer flush policy when full.
|
||||||
|
|
||||||
vsync_cb_t vsync_callback; // VSYNC callback.
|
omv_csi_cb_t vsync_cb; // VSYNC callback
|
||||||
frame_cb_t frame_callback; // Frame callback.
|
omv_csi_cb_t frame_cb; // Frame callback
|
||||||
|
|
||||||
// Sensor state
|
// Sensor state
|
||||||
omv_csi_sde_t sde; // Special digital effects
|
omv_csi_sde_t sde; // Special digital effects
|
||||||
@ -322,19 +336,22 @@ typedef struct _omv_csi {
|
|||||||
bool detected; // Set to true when the sensor is initialized.
|
bool detected; // Set to true when the sensor is initialized.
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
#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,
|
||||||
// dma handles, more I/Os etc... are included directly here,
|
// DMA handles, and additional I/Os, are included directly here.
|
||||||
// so that they can be accessible from this struct.
|
|
||||||
OMV_CSI_PORT_BITS
|
OMV_CSI_PORT_BITS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Can be used by port or image sensor drivers to store private
|
||||||
|
// data, internal state, or additional operations.
|
||||||
|
void *priv;
|
||||||
|
|
||||||
// Sensor function pointers
|
// Sensor function pointers
|
||||||
int (*reset) (omv_csi_t *csi);
|
int (*reset) (omv_csi_t *csi);
|
||||||
int (*sleep) (omv_csi_t *csi, int enable);
|
int (*sleep) (omv_csi_t *csi, int enable);
|
||||||
|
int (*match) (omv_csi_t *csi, size_t id);
|
||||||
int (*read_reg) (omv_csi_t *csi, uint16_t reg_addr);
|
int (*read_reg) (omv_csi_t *csi, uint16_t reg_addr);
|
||||||
int (*write_reg) (omv_csi_t *csi, uint16_t reg_addr, uint16_t reg_data);
|
int (*write_reg) (omv_csi_t *csi, uint16_t reg_addr, uint16_t reg_data);
|
||||||
int (*set_pixformat) (omv_csi_t *csi, pixformat_t pixformat);
|
int (*set_pixformat) (omv_csi_t *csi, pixformat_t pixformat);
|
||||||
@ -359,36 +376,44 @@ typedef struct _omv_csi {
|
|||||||
int (*set_special_effect) (omv_csi_t *csi, omv_csi_sde_t sde);
|
int (*set_special_effect) (omv_csi_t *csi, omv_csi_sde_t sde);
|
||||||
int (*set_lens_correction) (omv_csi_t *csi, int enable, int radi, int coef);
|
int (*set_lens_correction) (omv_csi_t *csi, int enable, int radi, int coef);
|
||||||
int (*ioctl) (omv_csi_t *csi, int request, va_list ap);
|
int (*ioctl) (omv_csi_t *csi, int request, va_list ap);
|
||||||
|
int (*config) (omv_csi_t *csi, omv_csi_config_t config);
|
||||||
|
int (*abort) (omv_csi_t *csi, bool fifo_flush, bool in_irq);
|
||||||
int (*snapshot) (omv_csi_t *csi, image_t *image, uint32_t flags);
|
int (*snapshot) (omv_csi_t *csi, image_t *image, uint32_t flags);
|
||||||
} omv_csi_t;
|
} omv_csi_t;
|
||||||
|
|
||||||
extern omv_csi_t csi;
|
// CSI array
|
||||||
extern omv_i2c_t csi_i2c;
|
extern omv_csi_t csi_all[OMV_CSI_MAX_DEVICES];
|
||||||
|
|
||||||
// Resolution table
|
// Resolution table
|
||||||
extern uint16_t resolution[][2];
|
extern uint16_t resolution[][2];
|
||||||
|
|
||||||
// Initialize the sensor state.
|
// Resets the sensor state on soft-reboots.
|
||||||
void omv_csi_init0();
|
void omv_csi_init0();
|
||||||
|
|
||||||
// Initialize the sensor and probe the image sensor.
|
// Initializes CSI struct with default ops.
|
||||||
int omv_csi_init();
|
int omv_csi_init();
|
||||||
|
|
||||||
|
// Return CSI instance.
|
||||||
|
// If id == -1, return the main csi, otherwise look up csi by chip-id.
|
||||||
|
omv_csi_t *omv_csi_get(int id);
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// Detect and initialize the image sensor.
|
||||||
int omv_csi_probe_init(uint32_t bus_id, uint32_t bus_speed);
|
int omv_csi_probe(omv_i2c_t *i2c);
|
||||||
|
|
||||||
|
// Match CSI chip ID with provided ID.
|
||||||
|
int omv_csi_match(omv_csi_t *csi, size_t id);
|
||||||
|
|
||||||
// This function is called after a setting that may require reconfiguring
|
// This function is called after a setting that may require reconfiguring
|
||||||
// the hardware changes, such as window size, frame size, or pixel format.
|
// the hardware changes, such as window size, frame size, or pixel format.
|
||||||
int omv_csi_config(omv_csi_config_t config);
|
int omv_csi_config(omv_csi_t *csi, omv_csi_config_t config);
|
||||||
|
|
||||||
// Abort frame capture and disable IRQs, DMA etc..
|
// Abort frame capture and disable IRQs, DMA etc..
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq);
|
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq);
|
||||||
|
|
||||||
// Reset the sensor to its default state.
|
// Reset the sensor to its default state.
|
||||||
int omv_csi_reset();
|
int omv_csi_reset(omv_csi_t *csi, bool hard);
|
||||||
|
|
||||||
// Return csi PID.
|
int omv_csi_get_id(omv_csi_t *csi);
|
||||||
int omv_csi_get_id();
|
|
||||||
|
|
||||||
// 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();
|
||||||
@ -397,144 +422,144 @@ uint32_t omv_csi_get_clk_frequency();
|
|||||||
int omv_csi_set_clk_frequency(uint32_t frequency);
|
int omv_csi_set_clk_frequency(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();
|
bool omv_csi_is_detected(omv_csi_t *csi);
|
||||||
|
|
||||||
// Sleep mode.
|
// Sleep mode.
|
||||||
int omv_csi_sleep(int enable);
|
int omv_csi_sleep(omv_csi_t *csi, int enable);
|
||||||
|
|
||||||
// Shutdown mode.
|
// Shutdown mode.
|
||||||
int omv_csi_shutdown(int enable);
|
int omv_csi_shutdown(omv_csi_t *csi, int enable);
|
||||||
|
|
||||||
// Read a csi register.
|
// Read a csi register.
|
||||||
int omv_csi_read_reg(uint16_t reg_addr);
|
int omv_csi_read_reg(omv_csi_t *csi, uint16_t reg_addr);
|
||||||
|
|
||||||
// Write a csi register.
|
// Write a csi register.
|
||||||
int omv_csi_write_reg(uint16_t reg_addr, uint16_t reg_data);
|
int omv_csi_write_reg(omv_csi_t *csi, uint16_t reg_addr, uint16_t reg_data);
|
||||||
|
|
||||||
// Set the sensor pixel format.
|
// Set the sensor pixel format.
|
||||||
int omv_csi_set_pixformat(pixformat_t pixformat);
|
int omv_csi_set_pixformat(omv_csi_t *csi, pixformat_t pixformat);
|
||||||
|
|
||||||
// Set the sensor frame size.
|
// Set the sensor frame size.
|
||||||
int omv_csi_set_framesize(omv_csi_framesize_t framesize);
|
int omv_csi_set_framesize(omv_csi_t *csi, omv_csi_framesize_t framesize);
|
||||||
|
|
||||||
// Set the sensor frame rate.
|
// Set the sensor frame rate.
|
||||||
int omv_csi_set_framerate(int framerate);
|
int omv_csi_set_framerate(omv_csi_t *csi, int framerate);
|
||||||
|
|
||||||
// Return the number of bytes per pixel to read from the image sensor.
|
// Return the number of bytes per pixel to read from the image sensor.
|
||||||
uint32_t omv_csi_get_src_bpp();
|
uint32_t omv_csi_get_src_bpp(omv_csi_t *csi);
|
||||||
|
|
||||||
// Return the number of bytes per pixel to write to memory.
|
// Return the number of bytes per pixel to write to memory.
|
||||||
uint32_t omv_csi_get_dst_bpp();
|
uint32_t omv_csi_get_dst_bpp(omv_csi_t *csi);
|
||||||
|
|
||||||
// Returns true if a crop is being applied to the frame buffer.
|
// Returns true if a crop is being applied to the frame buffer.
|
||||||
bool omv_csi_get_cropped();
|
bool omv_csi_get_cropped(omv_csi_t *csi);
|
||||||
|
|
||||||
// Set window size.
|
// Set window size.
|
||||||
int omv_csi_set_windowing(int x, int y, int w, int h);
|
int omv_csi_set_windowing(omv_csi_t *csi, int x, int y, int w, int h);
|
||||||
|
|
||||||
// Set the sensor contrast level (from -3 to +3).
|
// Set the sensor contrast level (from -3 to +3).
|
||||||
int omv_csi_set_contrast(int level);
|
int omv_csi_set_contrast(omv_csi_t *csi, int level);
|
||||||
|
|
||||||
// Set the sensor brightness level (from -3 to +3).
|
// Set the sensor brightness level (from -3 to +3).
|
||||||
int omv_csi_set_brightness(int level);
|
int omv_csi_set_brightness(omv_csi_t *csi, int level);
|
||||||
|
|
||||||
// Set the sensor saturation level (from -3 to +3).
|
// Set the sensor saturation level (from -3 to +3).
|
||||||
int omv_csi_set_saturation(int level);
|
int omv_csi_set_saturation(omv_csi_t *csi, int level);
|
||||||
|
|
||||||
// Set the sensor AGC gain ceiling.
|
// Set the sensor AGC gain ceiling.
|
||||||
// Note: This function has no effect when AGC (Automatic Gain Control) is disabled.
|
// Note: This function has no effect when AGC (Automatic Gain Control) is disabled.
|
||||||
int omv_csi_set_gainceiling(omv_csi_gainceiling_t gainceiling);
|
int omv_csi_set_gainceiling(omv_csi_t *csi, omv_csi_gainceiling_t gainceiling);
|
||||||
|
|
||||||
// Set the quantization scale factor, controls JPEG quality (quality 0-255).
|
// Set the quantization scale factor, controls JPEG quality (quality 0-255).
|
||||||
int omv_csi_set_quality(int qs);
|
int omv_csi_set_quality(omv_csi_t *csi, int qs);
|
||||||
|
|
||||||
// Enable/disable the colorbar mode.
|
// Enable/disable the colorbar mode.
|
||||||
int omv_csi_set_colorbar(int enable);
|
int omv_csi_set_colorbar(omv_csi_t *csi, int enable);
|
||||||
|
|
||||||
// Enable auto gain or set value manually.
|
// Enable auto gain or set value manually.
|
||||||
int omv_csi_set_auto_gain(int enable, float gain_db, float gain_db_ceiling);
|
int omv_csi_set_auto_gain(omv_csi_t *csi, int enable, float gain_db, float gain_db_ceiling);
|
||||||
|
|
||||||
// Get the gain value.
|
// Get the gain value.
|
||||||
int omv_csi_get_gain_db(float *gain_db);
|
int omv_csi_get_gain_db(omv_csi_t *csi, float *gain_db);
|
||||||
|
|
||||||
// Enable auto exposure or set value manually.
|
// Enable auto exposure or set value manually.
|
||||||
int omv_csi_set_auto_exposure(int enable, int exposure_us);
|
int omv_csi_set_auto_exposure(omv_csi_t *csi, int enable, int exposure_us);
|
||||||
|
|
||||||
// Get the exposure value.
|
// Get the exposure value.
|
||||||
int omv_csi_get_exposure_us(int *get_exposure_us);
|
int omv_csi_get_exposure_us(omv_csi_t *csi, int *get_exposure_us);
|
||||||
|
|
||||||
// Enable auto white balance or set value manually.
|
// Enable auto white balance or set value manually.
|
||||||
int omv_csi_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db);
|
int omv_csi_set_auto_whitebal(omv_csi_t *csi, int enable, float r_gain_db, float g_gain_db, float b_gain_db);
|
||||||
|
|
||||||
// Get the rgb gain values.
|
// Get the rgb gain values.
|
||||||
int omv_csi_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db);
|
int omv_csi_get_rgb_gain_db(omv_csi_t *csi, float *r_gain_db, float *g_gain_db, float *b_gain_db);
|
||||||
|
|
||||||
// Enable auto blc (black level calibration) or set from previous calibration.
|
// Enable auto blc (black level calibration) or set from previous calibration.
|
||||||
int omv_csi_set_auto_blc(int enable, int *regs);
|
int omv_csi_set_auto_blc(omv_csi_t *csi, int enable, int *regs);
|
||||||
|
|
||||||
// Get black level valibration register values.
|
// Get black level valibration register values.
|
||||||
int omv_csi_get_blc_regs(int *regs);
|
int omv_csi_get_blc_regs(omv_csi_t *csi, int *regs);
|
||||||
|
|
||||||
// Enable/disable the hmirror mode.
|
// Enable/disable the hmirror mode.
|
||||||
int omv_csi_set_hmirror(int enable);
|
int omv_csi_set_hmirror(omv_csi_t *csi, int enable);
|
||||||
|
|
||||||
// Get hmirror status.
|
// Get hmirror status.
|
||||||
bool omv_csi_get_hmirror();
|
bool omv_csi_get_hmirror(omv_csi_t *csi);
|
||||||
|
|
||||||
// Enable/disable the vflip mode.
|
// Enable/disable the vflip mode.
|
||||||
int omv_csi_set_vflip(int enable);
|
int omv_csi_set_vflip(omv_csi_t *csi, int enable);
|
||||||
|
|
||||||
// Get vflip status.
|
// Get vflip status.
|
||||||
bool omv_csi_get_vflip();
|
bool omv_csi_get_vflip(omv_csi_t *csi);
|
||||||
|
|
||||||
// Enable/disable the transpose mode.
|
// Enable/disable the transpose mode.
|
||||||
int omv_csi_set_transpose(bool enable);
|
int omv_csi_set_transpose(omv_csi_t *csi, bool enable);
|
||||||
|
|
||||||
// Get transpose mode state.
|
// Get transpose mode state.
|
||||||
bool omv_csi_get_transpose();
|
bool omv_csi_get_transpose(omv_csi_t *csi);
|
||||||
|
|
||||||
// Enable/disable the auto rotation mode.
|
// Enable/disable the auto rotation mode.
|
||||||
int omv_csi_set_auto_rotation(bool enable);
|
int omv_csi_set_auto_rotation(omv_csi_t *csi, bool enable);
|
||||||
|
|
||||||
// Get transpose mode state.
|
// Get transpose mode state.
|
||||||
bool omv_csi_get_auto_rotation();
|
bool omv_csi_get_auto_rotation(omv_csi_t *csi);
|
||||||
|
|
||||||
// Set the number of virtual frame buffers.
|
// Set the number of virtual frame buffers.
|
||||||
int omv_csi_set_framebuffers(int count);
|
int omv_csi_set_framebuffers(omv_csi_t *csi, int count);
|
||||||
|
|
||||||
// Drop the next frame to match the current frame rate.
|
// Drop the next frame to match the current frame rate.
|
||||||
void omv_csi_throttle_framerate();
|
void omv_csi_throttle_framerate(omv_csi_t *csi);
|
||||||
|
|
||||||
// Set special digital effects (SDE).
|
// Set special digital effects (SDE).
|
||||||
int omv_csi_set_special_effect(omv_csi_sde_t sde);
|
int omv_csi_set_special_effect(omv_csi_t *csi, omv_csi_sde_t sde);
|
||||||
|
|
||||||
// Set lens shading correction
|
// Set lens shading correction
|
||||||
int omv_csi_set_lens_correction(int enable, int radi, int coef);
|
int omv_csi_set_lens_correction(omv_csi_t *csi, int enable, int radi, int coef);
|
||||||
|
|
||||||
// IOCTL function
|
// IOCTL function
|
||||||
int omv_csi_ioctl(int request, ...);
|
int omv_csi_ioctl(omv_csi_t *csi, int request, ...);
|
||||||
|
|
||||||
// Set vsync callback function.
|
// Set vsync callback function.
|
||||||
int omv_csi_set_vsync_callback(vsync_cb_t vsync_cb);
|
int omv_csi_set_vsync_callback(omv_csi_t *csi, omv_csi_cb_t cb);
|
||||||
|
|
||||||
// Set frame callback function.
|
// Set frame callback function.
|
||||||
int omv_csi_set_frame_callback(frame_cb_t vsync_cb);
|
int omv_csi_set_frame_callback(omv_csi_t *csi, omv_csi_cb_t cb);
|
||||||
|
|
||||||
// Set color palette
|
// Set color palette
|
||||||
int omv_csi_set_color_palette(const uint16_t *color_palette);
|
int omv_csi_set_color_palette(omv_csi_t *csi, const uint16_t *color_palette);
|
||||||
|
|
||||||
// Get color palette
|
// Get color palette
|
||||||
const uint16_t *omv_csi_get_color_palette();
|
const uint16_t *omv_csi_get_color_palette(omv_csi_t *csi);
|
||||||
|
|
||||||
// Return true if the current frame size/format fits in RAM.
|
// Return true if the current frame size/format fits in RAM.
|
||||||
int omv_csi_check_framebuffer_size();
|
int omv_csi_check_framebuffer_size(omv_csi_t *csi);
|
||||||
|
|
||||||
// Auto-crop frame buffer until it fits in RAM (may switch pixel format to BAYER).
|
// Auto-crop frame buffer until it fits in RAM (may switch pixel format to BAYER).
|
||||||
int omv_csi_auto_crop_framebuffer();
|
int omv_csi_auto_crop_framebuffer(omv_csi_t *csi);
|
||||||
|
|
||||||
// Copy a single line buffer to its destination. The copying process is
|
// Copy a single line buffer to its destination. The copying process is
|
||||||
// DMA-accelerated, if available, and falls back to slow software if not.
|
// DMA-accelerated, if available, and falls back to slow software if not.
|
||||||
int omv_csi_copy_line(void *dma, uint8_t *src, uint8_t *dst);
|
int omv_csi_copy_line(omv_csi_t *csi, void *dma, uint8_t *src, uint8_t *dst);
|
||||||
|
|
||||||
// Default snapshot function.
|
// Default snapshot function.
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags);
|
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags);
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#if MICROPY_PY_CSI
|
#if MICROPY_PY_CSI || MICROPY_PY_CSI_NG
|
||||||
#include "omv_i2c.h"
|
#include "omv_i2c.h"
|
||||||
#include "omv_csi.h"
|
#include "omv_csi.h"
|
||||||
#endif
|
#endif
|
||||||
@ -146,8 +146,9 @@ void usbdbg_data_in(uint32_t size, usbdbg_write_callback_t write_callback) {
|
|||||||
case USBDBG_SENSOR_ID: {
|
case USBDBG_SENSOR_ID: {
|
||||||
uint32_t buffer = 0xFF;
|
uint32_t buffer = 0xFF;
|
||||||
#if MICROPY_PY_CSI
|
#if MICROPY_PY_CSI
|
||||||
if (omv_csi_is_detected() == true) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
buffer = omv_csi_get_id();
|
if (omv_csi_is_detected(csi) == true) {
|
||||||
|
buffer = omv_csi_get_id(csi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cmd = USBDBG_NONE;
|
cmd = USBDBG_NONE;
|
||||||
@ -363,21 +364,24 @@ void usbdbg_data_out(uint32_t size, usbdbg_read_callback_t read_callback) {
|
|||||||
struct {
|
struct {
|
||||||
int32_t name;
|
int32_t name;
|
||||||
int32_t value;
|
int32_t value;
|
||||||
}
|
} attr;
|
||||||
attr;
|
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
read_callback(&attr, sizeof(attr));
|
read_callback(&attr, sizeof(attr));
|
||||||
|
|
||||||
switch (attr.name) {
|
switch (attr.name) {
|
||||||
case OMV_CSI_ATTR_CONTRAST:
|
case OMV_CSI_ATTR_CONTRAST:
|
||||||
omv_csi_set_contrast(attr.value);
|
omv_csi_set_contrast(csi, attr.value);
|
||||||
break;
|
break;
|
||||||
case OMV_CSI_ATTR_BRIGHTNESS:
|
case OMV_CSI_ATTR_BRIGHTNESS:
|
||||||
omv_csi_set_brightness(attr.value);
|
omv_csi_set_brightness(csi, attr.value);
|
||||||
break;
|
break;
|
||||||
case OMV_CSI_ATTR_SATURATION:
|
case OMV_CSI_ATTR_SATURATION:
|
||||||
omv_csi_set_saturation(attr.value);
|
omv_csi_set_saturation(csi, attr.value);
|
||||||
break;
|
break;
|
||||||
case OMV_CSI_ATTR_GAINCEILING:
|
case OMV_CSI_ATTR_GAINCEILING:
|
||||||
omv_csi_set_gainceiling(attr.value);
|
omv_csi_set_gainceiling(csi, attr.value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
#define LEPTON_BOOT_TIMEOUT (1000)
|
#define LEPTON_BOOT_TIMEOUT (1000)
|
||||||
#define LEPTON_SNAPSHOT_RETRY (3)
|
#define LEPTON_SNAPSHOT_RETRY (3)
|
||||||
#define LEPTON_SNAPSHOT_TIMEOUT (10000)
|
#define LEPTON_SNAPSHOT_TIMEOUT (5000)
|
||||||
|
|
||||||
// Min/Max temperatures in Celsius.
|
// Min/Max temperatures in Celsius.
|
||||||
#define LEPTON_MIN_TEMP_NORM (-10.0f)
|
#define LEPTON_MIN_TEMP_NORM (-10.0f)
|
||||||
@ -73,18 +73,6 @@ static lepton_state_t lepton;
|
|||||||
|
|
||||||
static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mode);
|
static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mode);
|
||||||
|
|
||||||
static int sleep(omv_csi_t *csi, int enable) {
|
|
||||||
if (enable) {
|
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
|
||||||
mp_hal_delay_ms(100);
|
|
||||||
} else {
|
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
|
||||||
mp_hal_delay_ms(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_reg(omv_csi_t *csi, uint16_t reg_addr) {
|
static int read_reg(omv_csi_t *csi, uint16_t reg_addr) {
|
||||||
uint16_t reg_data;
|
uint16_t reg_data;
|
||||||
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, reg_addr, ®_data)) {
|
if (omv_i2c_readw2(csi->i2c, csi->slv_addr, reg_addr, ®_data)) {
|
||||||
@ -281,39 +269,49 @@ static int ioctl(omv_csi_t *csi, int request, va_list ap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mode) {
|
static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mode) {
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
|
||||||
mp_hal_delay_ms(10);
|
|
||||||
|
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
|
||||||
mp_hal_delay_ms(10);
|
|
||||||
|
|
||||||
omv_gpio_write(OMV_CSI_RESET_PIN, 0);
|
|
||||||
mp_hal_delay_ms(10);
|
|
||||||
|
|
||||||
omv_gpio_write(OMV_CSI_RESET_PIN, 1);
|
|
||||||
mp_hal_delay_ms(1000);
|
|
||||||
|
|
||||||
LEP_RAD_ENABLE_E rad;
|
LEP_RAD_ENABLE_E rad;
|
||||||
LEP_AGC_ROI_T roi;
|
LEP_AGC_ROI_T roi;
|
||||||
memset(&lepton.port, 0, sizeof(LEP_CAMERA_PORT_DESC_T));
|
memset(&lepton.port, 0, sizeof(LEP_CAMERA_PORT_DESC_T));
|
||||||
|
|
||||||
|
if (!csi->auxiliary) {
|
||||||
|
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
||||||
|
mp_hal_delay_ms(10);
|
||||||
|
|
||||||
|
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
||||||
|
mp_hal_delay_ms(10);
|
||||||
|
|
||||||
|
omv_gpio_write(OMV_CSI_RESET_PIN, 0);
|
||||||
|
mp_hal_delay_ms(10);
|
||||||
|
|
||||||
|
omv_gpio_write(OMV_CSI_RESET_PIN, 1);
|
||||||
|
mp_hal_delay_ms(1000);
|
||||||
|
}
|
||||||
|
|
||||||
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(1)) {
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(1)) {
|
||||||
if (LEP_OpenPort(csi->i2c, LEP_CCI_TWI, 0, &lepton.port) == LEP_OK) {
|
if (LEP_OpenPort(csi->i2c, LEP_CCI_TWI, 0, &lepton.port) == LEP_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (csi->auxiliary) {
|
||||||
|
LEP_RunOemReboot(&lepton.port);
|
||||||
|
mp_hal_delay_ms(1000);
|
||||||
|
}
|
||||||
|
|
||||||
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(1)) {
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(1)) {
|
||||||
LEP_SDK_BOOT_STATUS_E status;
|
LEP_SDK_BOOT_STATUS_E status;
|
||||||
if (LEP_GetCameraBootStatus(&lepton.port, &status) != LEP_OK) {
|
if (LEP_GetCameraBootStatus(&lepton.port, &status) != LEP_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == LEP_BOOT_STATUS_BOOTED) {
|
if (status == LEP_BOOT_STATUS_BOOTED) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -324,9 +322,11 @@ static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mo
|
|||||||
if (LEP_DirectReadRegister(&lepton.port, LEP_I2C_STATUS_REG, &status) != LEP_OK) {
|
if (LEP_DirectReadRegister(&lepton.port, LEP_I2C_STATUS_REG, &status) != LEP_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(status & LEP_I2C_STATUS_BUSY_BIT_MASK)) {
|
if (!(status & LEP_I2C_STATUS_BUSY_BIT_MASK)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
if ((mp_hal_ticks_ms() - start) >= LEPTON_BOOT_TIMEOUT) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -357,6 +357,14 @@ static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mo
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sleep(omv_csi_t *csi, int enable) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match(omv_csi_t *csi, size_t id) {
|
||||||
|
return (id == LEPTON_ID) || ((id >> 8) == LEPTON_ID);
|
||||||
|
}
|
||||||
|
|
||||||
static int reset(omv_csi_t *csi) {
|
static int reset(omv_csi_t *csi) {
|
||||||
vospi_deinit();
|
vospi_deinit();
|
||||||
|
|
||||||
@ -380,7 +388,23 @@ static int reset(omv_csi_t *csi) {
|
|||||||
|
|
||||||
static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
|
||||||
|
if (flags & OMV_CSI_CAPTURE_FLAGS_NBLOCK) {
|
||||||
|
if (!vospi_active()) {
|
||||||
|
// Start the capture without blocking
|
||||||
|
vospi_snapshot(0);
|
||||||
|
return OMV_CSI_ERROR_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If capture is running and no frames return.
|
||||||
|
if (!framebuffer_get_head(fb, FB_PEEK)) {
|
||||||
|
return OMV_CSI_ERROR_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & OMV_CSI_CAPTURE_FLAGS_UPDATE) {
|
||||||
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
|
}
|
||||||
|
|
||||||
if (csi->pixformat == PIXFORMAT_INVALID) {
|
if (csi->pixformat == PIXFORMAT_INVALID) {
|
||||||
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
||||||
@ -472,6 +496,9 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
int lepton_init(omv_csi_t *csi) {
|
int lepton_init(omv_csi_t *csi) {
|
||||||
csi->reset = reset;
|
csi->reset = reset;
|
||||||
csi->sleep = sleep;
|
csi->sleep = sleep;
|
||||||
|
csi->config = NULL;
|
||||||
|
csi->abort = NULL;
|
||||||
|
csi->match = match;
|
||||||
csi->snapshot = snapshot;
|
csi->snapshot = snapshot;
|
||||||
csi->read_reg = read_reg;
|
csi->read_reg = read_reg;
|
||||||
csi->write_reg = write_reg;
|
csi->write_reg = write_reg;
|
||||||
@ -495,12 +522,16 @@ int lepton_init(omv_csi_t *csi) {
|
|||||||
csi->set_lens_correction = set_lens_correction;
|
csi->set_lens_correction = set_lens_correction;
|
||||||
csi->ioctl = ioctl;
|
csi->ioctl = ioctl;
|
||||||
|
|
||||||
|
csi->auxiliary = 1;
|
||||||
csi->vsync_pol = 1;
|
csi->vsync_pol = 1;
|
||||||
csi->hsync_pol = 0;
|
csi->hsync_pol = 0;
|
||||||
csi->pixck_pol = 0;
|
csi->pixck_pol = 0;
|
||||||
csi->frame_sync = 0;
|
csi->frame_sync = 0;
|
||||||
csi->mono_bpp = 1;
|
csi->mono_bpp = 1;
|
||||||
|
|
||||||
|
// Extra delay after power-on
|
||||||
|
mp_hal_delay_ms(1000);
|
||||||
|
|
||||||
if (reset(csi) != 0) {
|
if (reset(csi) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,9 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
if (flags & OMV_CSI_CAPTURE_FLAGS_UPDATE) {
|
||||||
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
|
}
|
||||||
|
|
||||||
if (fb->n_buffers != 1) {
|
if (fb->n_buffers != 1) {
|
||||||
framebuffer_set_buffers(fb, 1);
|
framebuffer_set_buffers(fb, 1);
|
||||||
@ -149,12 +151,15 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
|
|
||||||
int softcsi_init(omv_csi_t *csi) {
|
int softcsi_init(omv_csi_t *csi) {
|
||||||
csi->reset = reset;
|
csi->reset = reset;
|
||||||
|
csi->abort = NULL;
|
||||||
|
csi->config = NULL;
|
||||||
csi->set_pixformat = set_pixformat;
|
csi->set_pixformat = set_pixformat;
|
||||||
csi->set_framesize = set_framesize;
|
csi->set_framesize = set_framesize;
|
||||||
csi->set_hmirror = set_hmirror;
|
csi->set_hmirror = set_hmirror;
|
||||||
csi->set_vflip = set_vflip;
|
csi->set_vflip = set_vflip;
|
||||||
csi->snapshot = snapshot;
|
csi->snapshot = snapshot;
|
||||||
|
|
||||||
|
csi->auxiliary = 1;
|
||||||
csi->vsync_pol = 1;
|
csi->vsync_pol = 1;
|
||||||
csi->hsync_pol = 0;
|
csi->hsync_pol = 0;
|
||||||
csi->pixck_pol = 0;
|
csi->pixck_pol = 0;
|
||||||
|
@ -42,26 +42,28 @@ extern char _jpeg_memory_end;
|
|||||||
jpegbuffer_t *jpegbuffer = (jpegbuffer_t *) &_jpeg_memory_start;
|
jpegbuffer_t *jpegbuffer = (jpegbuffer_t *) &_jpeg_memory_start;
|
||||||
|
|
||||||
void framebuffer_init0() {
|
void framebuffer_init0() {
|
||||||
// Save fb_enabled flag state
|
// Save enable flag.
|
||||||
int fb_enabled = jpegbuffer->enabled;
|
int fb_enabled = jpegbuffer->enabled;
|
||||||
|
uint32_t fb_size = (char *) &_fb_memory_end - (char *) framebuffer->data;
|
||||||
|
|
||||||
// Clear framebuffers
|
// Initialize frame buffer.
|
||||||
memset(framebuffer, 0, sizeof(*framebuffer));
|
framebuffer_init_fb(framebuffer, fb_size, false);
|
||||||
|
|
||||||
|
// Initialize jpeg buffer.
|
||||||
memset(jpegbuffer, 0, sizeof(*jpegbuffer));
|
memset(jpegbuffer, 0, sizeof(*jpegbuffer));
|
||||||
|
|
||||||
mutex_init0(&jpegbuffer->lock);
|
mutex_init0(&jpegbuffer->lock);
|
||||||
|
jpegbuffer->enabled = fb_enabled;
|
||||||
// Enable streaming.
|
|
||||||
framebuffer->streaming_enabled = true; // controlled by the OpenMV Cam.
|
|
||||||
|
|
||||||
// Set default quality
|
|
||||||
jpegbuffer->quality = ((OMV_JPEG_QUALITY_HIGH - OMV_JPEG_QUALITY_LOW) / 2) + OMV_JPEG_QUALITY_LOW;
|
jpegbuffer->quality = ((OMV_JPEG_QUALITY_HIGH - OMV_JPEG_QUALITY_LOW) / 2) + OMV_JPEG_QUALITY_LOW;
|
||||||
|
}
|
||||||
|
|
||||||
// Set fb_enabled
|
void framebuffer_init_fb(framebuffer_t *fb, size_t size, bool dynamic) {
|
||||||
jpegbuffer->enabled = fb_enabled; // controlled by the IDE.
|
// Clear framebuffers
|
||||||
|
memset(fb, 0, sizeof(*fb));
|
||||||
|
|
||||||
// Setup buffering.
|
fb->raw_size = size;
|
||||||
framebuffer_set_buffers(framebuffer, 1);
|
fb->streaming_enabled = true;
|
||||||
|
fb->dynamic = dynamic;
|
||||||
|
framebuffer_set_buffers(fb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_init_image(framebuffer_t *fb, image_t *img) {
|
void framebuffer_init_image(framebuffer_t *fb, image_t *img) {
|
||||||
@ -283,8 +285,14 @@ int framebuffer_encoded_size(framebuffer_t *fb, image_t *img) {
|
|||||||
|
|
||||||
// Returns the current frame buffer size, factoring in the space taken by fb_alloc.
|
// Returns the current frame buffer size, factoring in the space taken by fb_alloc.
|
||||||
static uint32_t framebuffer_max_buffer_size(framebuffer_t *fb) {
|
static uint32_t framebuffer_max_buffer_size(framebuffer_t *fb) {
|
||||||
uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN((char *) &_fb_memory_end - (char *) fb->data);
|
uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN(fb->raw_size);
|
||||||
uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) fb->data);
|
uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) fb->data);
|
||||||
|
|
||||||
|
// No fb_alloc on dynamic FBs.
|
||||||
|
if (fb->dynamic) {
|
||||||
|
fb_avail_size = fb_total_size;
|
||||||
|
}
|
||||||
|
|
||||||
return IM_MIN(fb_total_size, fb_avail_size);
|
return IM_MIN(fb_total_size, fb_avail_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ typedef struct framebuffer {
|
|||||||
int32_t u, v;
|
int32_t u, v;
|
||||||
PIXFORMAT_STRUCT;
|
PIXFORMAT_STRUCT;
|
||||||
int32_t streaming_enabled;
|
int32_t streaming_enabled;
|
||||||
|
uint32_t raw_size;
|
||||||
uint32_t buff_size;
|
uint32_t buff_size;
|
||||||
uint32_t n_buffers;
|
uint32_t n_buffers;
|
||||||
uint32_t frame_size;
|
uint32_t frame_size;
|
||||||
@ -50,6 +51,7 @@ typedef struct framebuffer {
|
|||||||
volatile int32_t tail;
|
volatile int32_t tail;
|
||||||
bool check_head;
|
bool check_head;
|
||||||
int32_t sampled_head;
|
int32_t sampled_head;
|
||||||
|
bool dynamic;
|
||||||
OMV_ATTR_ALIGNED(uint8_t data[], FRAMEBUFFER_ALIGNMENT);
|
OMV_ATTR_ALIGNED(uint8_t data[], FRAMEBUFFER_ALIGNMENT);
|
||||||
} framebuffer_t;
|
} framebuffer_t;
|
||||||
|
|
||||||
@ -108,6 +110,9 @@ uint32_t framebuffer_get_buffer_size(framebuffer_t *fb);
|
|||||||
// Return the state of a buffer.
|
// Return the state of a buffer.
|
||||||
vbuffer_t *framebuffer_get_buffer(framebuffer_t *fb, int32_t index);
|
vbuffer_t *framebuffer_get_buffer(framebuffer_t *fb, int32_t index);
|
||||||
|
|
||||||
|
// Initializes a frame buffer instance.
|
||||||
|
void framebuffer_init_fb(framebuffer_t *fb, size_t size, bool dynamic);
|
||||||
|
|
||||||
// Initializes an image from the frame buffer.
|
// Initializes an image from the frame buffer.
|
||||||
void framebuffer_init_image(framebuffer_t *fb, image_t *img);
|
void framebuffer_init_image(framebuffer_t *fb, image_t *img);
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ void image_init(image_t *ptr, int w, int h, pixformat_t pixfmt, uint32_t size, v
|
|||||||
ptr->pixels = pixels;
|
ptr->pixels = pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void image_copy(image_t *dst, image_t *src) {
|
void image_copy(image_t *dst, image_t *src, bool deep) {
|
||||||
memcpy(dst, src, sizeof(image_t));
|
memcpy(dst, src, sizeof(image_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +570,7 @@ typedef struct image {
|
|||||||
void image_xalloc(image_t *img, size_t size);
|
void image_xalloc(image_t *img, size_t size);
|
||||||
void image_xalloc0(image_t *img, size_t size);
|
void image_xalloc0(image_t *img, size_t size);
|
||||||
void image_init(image_t *ptr, int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels);
|
void image_init(image_t *ptr, int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels);
|
||||||
void image_copy(image_t *dst, image_t *src);
|
void image_copy(image_t *dst, image_t *src, bool deep);
|
||||||
size_t image_line_size(image_t *ptr);
|
size_t image_line_size(image_t *ptr);
|
||||||
size_t image_size(image_t *ptr);
|
size_t image_size(image_t *ptr);
|
||||||
bool image_get_mask_pixel(image_t *ptr, int x, int y);
|
bool image_get_mask_pixel(image_t *ptr, int x, int y);
|
||||||
|
330
modules/py_csi.c
330
modules/py_csi.c
@ -38,6 +38,8 @@
|
|||||||
#if MICROPY_PY_CSI
|
#if MICROPY_PY_CSI
|
||||||
|
|
||||||
#include "omv_csi.h"
|
#include "omv_csi.h"
|
||||||
|
#include "omv_gpio.h"
|
||||||
|
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "py_assert.h"
|
#include "py_assert.h"
|
||||||
@ -50,7 +52,6 @@
|
|||||||
#include "py_helper.h"
|
#include "py_helper.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
|
|
||||||
extern omv_csi_t csi;
|
|
||||||
static mp_obj_t vsync_callback = mp_const_none;
|
static mp_obj_t vsync_callback = mp_const_none;
|
||||||
static mp_obj_t frame_callback = mp_const_none;
|
static mp_obj_t frame_callback = mp_const_none;
|
||||||
|
|
||||||
@ -58,8 +59,8 @@ static mp_obj_t frame_callback = mp_const_none;
|
|||||||
#define omv_csi_print_error(op) printf("\x1B[31mWARNING: %s control is not supported by this image sensor.\x1B[0m\n", op);
|
#define omv_csi_print_error(op) printf("\x1B[31mWARNING: %s control is not supported by this image sensor.\x1B[0m\n", op);
|
||||||
|
|
||||||
#if MICROPY_PY_IMU
|
#if MICROPY_PY_IMU
|
||||||
static void do_auto_rotation(int pitch_deadzone, int roll_activezone) {
|
static void do_auto_rotation(omv_csi_t *csi, int pitch_deadzone, int roll_activezone) {
|
||||||
if (omv_csi_get_auto_rotation()) {
|
if (omv_csi_get_auto_rotation(csi)) {
|
||||||
float pitch = py_imu_pitch_rotation();
|
float pitch = py_imu_pitch_rotation();
|
||||||
if (((pitch <= (90 - pitch_deadzone)) || ((90 + pitch_deadzone) < pitch))
|
if (((pitch <= (90 - pitch_deadzone)) || ((90 + pitch_deadzone) < pitch))
|
||||||
&& ((pitch <= (270 - pitch_deadzone)) || ((270 + pitch_deadzone) < pitch))) {
|
&& ((pitch <= (270 - pitch_deadzone)) || ((270 + pitch_deadzone) < pitch))) {
|
||||||
@ -67,24 +68,24 @@ static void do_auto_rotation(int pitch_deadzone, int roll_activezone) {
|
|||||||
float roll = py_imu_roll_rotation();
|
float roll = py_imu_roll_rotation();
|
||||||
if (((360 - roll_activezone) <= roll) || (roll < (0 + roll_activezone)) ) {
|
if (((360 - roll_activezone) <= roll) || (roll < (0 + roll_activezone)) ) {
|
||||||
// center is 0/360, upright
|
// center is 0/360, upright
|
||||||
omv_csi_set_hmirror(false);
|
omv_csi_set_hmirror(csi, false);
|
||||||
omv_csi_set_vflip(false);
|
omv_csi_set_vflip(csi, false);
|
||||||
omv_csi_set_transpose(false);
|
omv_csi_set_transpose(csi, false);
|
||||||
} else if (((270 - roll_activezone) <= roll) && (roll < (270 + roll_activezone))) {
|
} else if (((270 - roll_activezone) <= roll) && (roll < (270 + roll_activezone))) {
|
||||||
// center is 270, rotated right
|
// center is 270, rotated right
|
||||||
omv_csi_set_hmirror(true);
|
omv_csi_set_hmirror(csi, true);
|
||||||
omv_csi_set_vflip(false);
|
omv_csi_set_vflip(csi, false);
|
||||||
omv_csi_set_transpose(true);
|
omv_csi_set_transpose(csi, true);
|
||||||
} else if (((180 - roll_activezone) <= roll) && (roll < (180 + roll_activezone))) {
|
} else if (((180 - roll_activezone) <= roll) && (roll < (180 + roll_activezone))) {
|
||||||
// center is 180, upside down
|
// center is 180, upside down
|
||||||
omv_csi_set_hmirror(true);
|
omv_csi_set_hmirror(csi, true);
|
||||||
omv_csi_set_vflip(true);
|
omv_csi_set_vflip(csi, true);
|
||||||
omv_csi_set_transpose(false);
|
omv_csi_set_transpose(csi, false);
|
||||||
} else if (((90 - roll_activezone) <= roll) && (roll < (90 + roll_activezone))) {
|
} else if (((90 - roll_activezone) <= roll) && (roll < (90 + roll_activezone))) {
|
||||||
// center is 90, rotated left
|
// center is 90, rotated left
|
||||||
omv_csi_set_hmirror(false);
|
omv_csi_set_hmirror(csi, false);
|
||||||
omv_csi_set_vflip(true);
|
omv_csi_set_vflip(csi, true);
|
||||||
omv_csi_set_transpose(true);
|
omv_csi_set_transpose(csi, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,10 +93,11 @@ static void do_auto_rotation(int pitch_deadzone, int roll_activezone) {
|
|||||||
#endif // MICROPY_PY_IMU
|
#endif // MICROPY_PY_IMU
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi__init__() {
|
static mp_obj_t py_omv_csi__init__() {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
// This is the module init function, not the sensor init function.
|
// This is the module init function, not the sensor init function.
|
||||||
// This gets called when the module is imported, so it's a good
|
// This gets called when the module is imported, so it's a good
|
||||||
// place to check if the sensor was detected or not.
|
// place to check if the sensor was detected or not.
|
||||||
if (omv_csi_is_detected() == false) {
|
if (omv_csi_is_detected(csi) == false) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_ISC_UNDETECTED);
|
omv_csi_raise_error(OMV_CSI_ERROR_ISC_UNDETECTED);
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
@ -103,14 +105,16 @@ static mp_obj_t py_omv_csi__init__() {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi__init__obj, py_omv_csi__init__);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi__init__obj, py_omv_csi__init__);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_reset() {
|
static mp_obj_t py_omv_csi_reset() {
|
||||||
int error = omv_csi_reset();
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
|
int error = omv_csi_reset(csi, true);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
#if MICROPY_PY_IMU
|
#if MICROPY_PY_IMU
|
||||||
// +-10 degree dead-zone around pitch 90/270.
|
// +-10 degree dead-zone around pitch 90/270.
|
||||||
// +-45 degree active-zone around roll 0/90/180/270/360.
|
// +-45 degree active-zone around roll 0/90/180/270/360.
|
||||||
do_auto_rotation(10, 45);
|
do_auto_rotation(csi, 10, 45);
|
||||||
// We're setting the dead-zone on pitch because roll readings are invalid there.
|
// We're setting the dead-zone on pitch because roll readings are invalid there.
|
||||||
// We're setting the full range on roll to set the initial state.
|
// We're setting the full range on roll to set the initial state.
|
||||||
#endif // MICROPY_PY_IMU
|
#endif // MICROPY_PY_IMU
|
||||||
@ -119,34 +123,41 @@ static mp_obj_t py_omv_csi_reset() {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_reset_obj, py_omv_csi_reset);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_reset_obj, py_omv_csi_reset);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_sleep(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_sleep(mp_obj_t enable) {
|
||||||
PY_ASSERT_FALSE_MSG(omv_csi_sleep(mp_obj_is_true(enable)) != 0, "Sleep Failed");
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
PY_ASSERT_FALSE_MSG(omv_csi_sleep(csi, mp_obj_is_true(enable)) != 0, "Sleep Failed");
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_sleep_obj, py_omv_csi_sleep);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_sleep_obj, py_omv_csi_sleep);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_shutdown(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_shutdown(mp_obj_t enable) {
|
||||||
PY_ASSERT_FALSE_MSG(omv_csi_shutdown(mp_obj_is_true(enable)) != 0, "Shutdown Failed");
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
PY_ASSERT_FALSE_MSG(omv_csi_shutdown(csi, mp_obj_is_true(enable)) != 0, "Shutdown Failed");
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_shutdown_obj, py_omv_csi_shutdown);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_shutdown_obj, py_omv_csi_shutdown);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_flush() {
|
static mp_obj_t py_omv_csi_flush() {
|
||||||
framebuffer_update_jpeg_buffer(csi.fb);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
framebuffer_update_jpeg_buffer(csi->fb);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_flush_obj, py_omv_csi_flush);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_flush_obj, py_omv_csi_flush);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_snapshot(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
static mp_obj_t py_omv_csi_snapshot(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
#if MICROPY_PY_IMU
|
#if MICROPY_PY_IMU
|
||||||
// +-10 degree dead-zone around pitch 90/270.
|
// +-10 degree dead-zone around pitch 90/270.
|
||||||
// +-35 degree active-zone around roll 0/90/180/270/360.
|
// +-35 degree active-zone around roll 0/90/180/270/360.
|
||||||
do_auto_rotation(10, 35);
|
do_auto_rotation(csi, 10, 35);
|
||||||
// We're setting the dead-zone on pitch because roll readings are invalid there.
|
// We're setting the dead-zone on pitch because roll readings are invalid there.
|
||||||
// We're not setting the full range on roll to prevent oscillation.
|
// We're not setting the full range on roll to prevent oscillation.
|
||||||
#endif // MICROPY_PY_IMU
|
#endif // MICROPY_PY_IMU
|
||||||
|
|
||||||
mp_obj_t image = py_image(0, 0, 0, 0, 0);
|
mp_obj_t image = py_image(0, 0, 0, 0, 0);
|
||||||
int error = csi.snapshot(&csi, (image_t *) py_image_cobj(image), 0);
|
uint32_t flags = OMV_CSI_CAPTURE_FLAGS_UPDATE;
|
||||||
|
|
||||||
|
int error = omv_csi_snapshot(csi, (image_t *) py_image_cobj(image), flags);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -184,34 +195,39 @@ static mp_obj_t py_omv_csi_skip_frames(size_t n_args, const mp_obj_t *args, mp_m
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_skip_frames_obj, 0, py_omv_csi_skip_frames);
|
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_skip_frames_obj, 0, py_omv_csi_skip_frames);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_width() {
|
static mp_obj_t py_omv_csi_width() {
|
||||||
return mp_obj_new_int(resolution[csi.framesize][0]);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_int(resolution[csi->framesize][0]);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_width_obj, py_omv_csi_width);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_width_obj, py_omv_csi_width);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_height() {
|
static mp_obj_t py_omv_csi_height() {
|
||||||
return mp_obj_new_int(resolution[csi.framesize][1]);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_int(resolution[csi->framesize][1]);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_height_obj, py_omv_csi_height);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_height_obj, py_omv_csi_height);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_fb() {
|
static mp_obj_t py_omv_csi_get_fb() {
|
||||||
image_t image;
|
image_t image;
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
if (framebuffer_get_depth(csi.fb) < 0) {
|
if (framebuffer_get_depth(csi->fb) < 0) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer_init_image(csi.fb, &image);
|
framebuffer_init_image(csi->fb, &image);
|
||||||
return py_image_from_struct(&image);
|
return py_image_from_struct(&image);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_fb_obj, py_omv_csi_get_fb);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_fb_obj, py_omv_csi_get_fb);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_id() {
|
static mp_obj_t py_omv_csi_get_id() {
|
||||||
return mp_obj_new_int(omv_csi_get_id());
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_int(omv_csi_get_id(csi));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_id_obj, py_omv_csi_get_id);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_id_obj, py_omv_csi_get_id);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_frame_available() {
|
static mp_obj_t py_omv_csi_get_frame_available() {
|
||||||
framebuffer_t *fb = framebuffer_get(0);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
return mp_obj_new_bool(fb->tail != fb->head);
|
return mp_obj_new_bool(fb->tail != fb->head);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_frame_available_obj, py_omv_csi_get_frame_available);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_frame_available_obj, py_omv_csi_get_frame_available);
|
||||||
@ -245,7 +261,8 @@ static mp_obj_t py_omv_csi_dealloc_extra_fb() {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_dealloc_extra_fb_obj, py_omv_csi_dealloc_extra_fb);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_dealloc_extra_fb_obj, py_omv_csi_dealloc_extra_fb);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_pixformat(mp_obj_t pixformat) {
|
static mp_obj_t py_omv_csi_set_pixformat(mp_obj_t pixformat) {
|
||||||
int error = omv_csi_set_pixformat(mp_obj_get_int(pixformat));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_pixformat(csi, mp_obj_get_int(pixformat));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -254,15 +271,17 @@ static mp_obj_t py_omv_csi_set_pixformat(mp_obj_t pixformat) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_pixformat_obj, py_omv_csi_set_pixformat);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_pixformat_obj, py_omv_csi_set_pixformat);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_pixformat() {
|
static mp_obj_t py_omv_csi_get_pixformat() {
|
||||||
if (csi.pixformat == PIXFORMAT_INVALID) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (csi->pixformat == PIXFORMAT_INVALID) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_PIXFORMAT);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_PIXFORMAT);
|
||||||
}
|
}
|
||||||
return mp_obj_new_int(csi.pixformat);
|
return mp_obj_new_int(csi->pixformat);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_pixformat_obj, py_omv_csi_get_pixformat);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_pixformat_obj, py_omv_csi_get_pixformat);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_framesize(mp_obj_t framesize) {
|
static mp_obj_t py_omv_csi_set_framesize(mp_obj_t framesize) {
|
||||||
int error = omv_csi_set_framesize(mp_obj_get_int(framesize));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_framesize(csi, mp_obj_get_int(framesize));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -271,15 +290,17 @@ static mp_obj_t py_omv_csi_set_framesize(mp_obj_t framesize) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framesize_obj, py_omv_csi_set_framesize);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framesize_obj, py_omv_csi_set_framesize);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_framesize() {
|
static mp_obj_t py_omv_csi_get_framesize() {
|
||||||
if (csi.framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (csi->framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
||||||
}
|
}
|
||||||
return mp_obj_new_int(csi.framesize);
|
return mp_obj_new_int(csi->framesize);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framesize_obj, py_omv_csi_get_framesize);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framesize_obj, py_omv_csi_get_framesize);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_framerate(mp_obj_t framerate) {
|
static mp_obj_t py_omv_csi_set_framerate(mp_obj_t framerate) {
|
||||||
int error = omv_csi_set_framerate(mp_obj_get_int(framerate));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_framerate(csi, mp_obj_get_int(framerate));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -288,23 +309,25 @@ static mp_obj_t py_omv_csi_set_framerate(mp_obj_t framerate) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framerate_obj, py_omv_csi_set_framerate);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framerate_obj, py_omv_csi_set_framerate);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_framerate() {
|
static mp_obj_t py_omv_csi_get_framerate() {
|
||||||
if (csi.framerate == 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (csi->framerate == 0) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMERATE);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMERATE);
|
||||||
}
|
}
|
||||||
return mp_obj_new_int(csi.framerate);
|
return mp_obj_new_int(csi->framerate);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framerate_obj, py_omv_csi_get_framerate);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framerate_obj, py_omv_csi_get_framerate);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_windowing(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t py_omv_csi_set_windowing(size_t n_args, const mp_obj_t *args) {
|
||||||
if (csi.framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (csi->framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
rectangle_t temp;
|
rectangle_t temp;
|
||||||
temp.x = 0;
|
temp.x = 0;
|
||||||
temp.y = 0;
|
temp.y = 0;
|
||||||
temp.w = resolution[csi.framesize][0];
|
temp.w = resolution[csi->framesize][0];
|
||||||
temp.h = resolution[csi.framesize][1];
|
temp.h = resolution[csi->framesize][1];
|
||||||
|
|
||||||
mp_obj_t *array = (mp_obj_t *) args;
|
mp_obj_t *array = (mp_obj_t *) args;
|
||||||
mp_uint_t array_len = n_args;
|
mp_uint_t array_len = n_args;
|
||||||
@ -339,7 +362,7 @@ static mp_obj_t py_omv_csi_set_windowing(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
rectangle_intersected(&r, &temp);
|
rectangle_intersected(&r, &temp);
|
||||||
|
|
||||||
int error = omv_csi_set_windowing(r.x, r.y, r.w, r.h);
|
int error = omv_csi_set_windowing(csi, r.x, r.y, r.w, r.h);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -349,18 +372,20 @@ static mp_obj_t py_omv_csi_set_windowing(size_t n_args, const mp_obj_t *args) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_set_windowing_obj, 1, 4, py_omv_csi_set_windowing);
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_set_windowing_obj, 1, 4, py_omv_csi_set_windowing);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_windowing() {
|
static mp_obj_t py_omv_csi_get_windowing() {
|
||||||
if (csi.framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (csi->framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_FRAMESIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(framebuffer_get_x(csi.fb)),
|
return mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(framebuffer_get_x(csi->fb)),
|
||||||
mp_obj_new_int(framebuffer_get_y(csi.fb)),
|
mp_obj_new_int(framebuffer_get_y(csi->fb)),
|
||||||
mp_obj_new_int(framebuffer_get_u(csi.fb)),
|
mp_obj_new_int(framebuffer_get_u(csi->fb)),
|
||||||
mp_obj_new_int(framebuffer_get_v(csi.fb))});
|
mp_obj_new_int(framebuffer_get_v(csi->fb))});
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_windowing_obj, py_omv_csi_get_windowing);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_windowing_obj, py_omv_csi_get_windowing);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_gainceiling(mp_obj_t gainceiling) {
|
static mp_obj_t py_omv_csi_set_gainceiling(mp_obj_t gainceiling) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
omv_csi_gainceiling_t gain;
|
omv_csi_gainceiling_t gain;
|
||||||
switch (mp_obj_get_int(gainceiling)) {
|
switch (mp_obj_get_int(gainceiling)) {
|
||||||
case 2:
|
case 2:
|
||||||
@ -389,7 +414,7 @@ static mp_obj_t py_omv_csi_set_gainceiling(mp_obj_t gainceiling) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (omv_csi_set_gainceiling(gain) != 0) {
|
if (omv_csi_set_gainceiling(csi, gain) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -397,7 +422,8 @@ static mp_obj_t py_omv_csi_set_gainceiling(mp_obj_t gainceiling) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_gainceiling_obj, py_omv_csi_set_gainceiling);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_gainceiling_obj, py_omv_csi_set_gainceiling);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_brightness(mp_obj_t brightness) {
|
static mp_obj_t py_omv_csi_set_brightness(mp_obj_t brightness) {
|
||||||
if (omv_csi_set_brightness(mp_obj_get_int(brightness)) != 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_brightness(csi, mp_obj_get_int(brightness)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -405,7 +431,8 @@ static mp_obj_t py_omv_csi_set_brightness(mp_obj_t brightness) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_brightness_obj, py_omv_csi_set_brightness);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_brightness_obj, py_omv_csi_set_brightness);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_contrast(mp_obj_t contrast) {
|
static mp_obj_t py_omv_csi_set_contrast(mp_obj_t contrast) {
|
||||||
if (omv_csi_set_contrast(mp_obj_get_int(contrast)) != 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_contrast(csi, mp_obj_get_int(contrast)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -413,7 +440,8 @@ static mp_obj_t py_omv_csi_set_contrast(mp_obj_t contrast) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_contrast_obj, py_omv_csi_set_contrast);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_contrast_obj, py_omv_csi_set_contrast);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_saturation(mp_obj_t saturation) {
|
static mp_obj_t py_omv_csi_set_saturation(mp_obj_t saturation) {
|
||||||
if (omv_csi_set_saturation(mp_obj_get_int(saturation)) != 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_saturation(csi, mp_obj_get_int(saturation)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -421,12 +449,13 @@ static mp_obj_t py_omv_csi_set_saturation(mp_obj_t saturation) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_saturation_obj, py_omv_csi_set_saturation);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_saturation_obj, py_omv_csi_set_saturation);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_quality(mp_obj_t qs) {
|
static mp_obj_t py_omv_csi_set_quality(mp_obj_t qs) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int q = mp_obj_get_int(qs);
|
int q = mp_obj_get_int(qs);
|
||||||
PY_ASSERT_TRUE((q >= 0 && q <= 100));
|
PY_ASSERT_TRUE((q >= 0 && q <= 100));
|
||||||
|
|
||||||
q = 100 - q; //invert quality
|
q = 100 - q; //invert quality
|
||||||
q = 255 * q / 100; //map to 0->255
|
q = 255 * q / 100; //map to 0->255
|
||||||
if (omv_csi_set_quality(q) != 0) {
|
if (omv_csi_set_quality(csi, q) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -434,7 +463,8 @@ static mp_obj_t py_omv_csi_set_quality(mp_obj_t qs) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_quality_obj, py_omv_csi_set_quality);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_quality_obj, py_omv_csi_set_quality);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_colorbar(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_set_colorbar(mp_obj_t enable) {
|
||||||
if (omv_csi_set_colorbar(mp_obj_is_true(enable)) != 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_colorbar(csi, mp_obj_is_true(enable)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -449,6 +479,7 @@ static mp_obj_t py_omv_csi_set_auto_gain(size_t n_args, const mp_obj_t *pos_args
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Parse args.
|
// Parse args.
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int enable = mp_obj_get_int(pos_args[0]);
|
int enable = mp_obj_get_int(pos_args[0]);
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
@ -456,7 +487,7 @@ static mp_obj_t py_omv_csi_set_auto_gain(size_t n_args, const mp_obj_t *pos_args
|
|||||||
float gain_db = py_helper_arg_to_float(args[ARG_gain_db].u_obj, NAN);
|
float gain_db = py_helper_arg_to_float(args[ARG_gain_db].u_obj, NAN);
|
||||||
float gain_db_ceiling = py_helper_arg_to_float(args[ARG_gain_db_ceiling].u_obj, NAN);
|
float gain_db_ceiling = py_helper_arg_to_float(args[ARG_gain_db_ceiling].u_obj, NAN);
|
||||||
|
|
||||||
int error = omv_csi_set_auto_gain(enable, gain_db, gain_db_ceiling);
|
int error = omv_csi_set_auto_gain(csi, enable, gain_db, gain_db_ceiling);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
@ -468,8 +499,9 @@ static mp_obj_t py_omv_csi_set_auto_gain(size_t n_args, const mp_obj_t *pos_args
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_gain_obj, 1, py_omv_csi_set_auto_gain);
|
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_gain_obj, 1, py_omv_csi_set_auto_gain);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_gain_db() {
|
static mp_obj_t py_omv_csi_get_gain_db() {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
float gain_db;
|
float gain_db;
|
||||||
int error = omv_csi_get_gain_db(&gain_db);
|
int error = omv_csi_get_gain_db(csi, &gain_db);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -484,11 +516,12 @@ static mp_obj_t py_omv_csi_set_auto_exposure(size_t n_args, const mp_obj_t *pos_
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Parse args.
|
// Parse args.
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int enable = mp_obj_get_int(pos_args[0]);
|
int enable = mp_obj_get_int(pos_args[0]);
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
int error = omv_csi_set_auto_exposure(enable, args[ARG_exposure_us].u_int);
|
int error = omv_csi_set_auto_exposure(csi, enable, args[ARG_exposure_us].u_int);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
@ -501,7 +534,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_exposure_obj, 1, py_omv_cs
|
|||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_exposure_us() {
|
static mp_obj_t py_omv_csi_get_exposure_us() {
|
||||||
int exposure_us;
|
int exposure_us;
|
||||||
int error = omv_csi_get_exposure_us(&exposure_us);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_get_exposure_us(csi, &exposure_us);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -516,6 +550,7 @@ static mp_obj_t py_omv_csi_set_auto_whitebal(size_t n_args, const mp_obj_t *pos_
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Parse args.
|
// Parse args.
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int enable = mp_obj_get_int(pos_args[0]);
|
int enable = mp_obj_get_int(pos_args[0]);
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
@ -523,7 +558,7 @@ static mp_obj_t py_omv_csi_set_auto_whitebal(size_t n_args, const mp_obj_t *pos_
|
|||||||
float rgb_gain_db[3] = {NAN, NAN, NAN};
|
float rgb_gain_db[3] = {NAN, NAN, NAN};
|
||||||
py_helper_arg_to_float_array(args[ARG_rgb_gain_db].u_obj, rgb_gain_db, 3);
|
py_helper_arg_to_float_array(args[ARG_rgb_gain_db].u_obj, rgb_gain_db, 3);
|
||||||
|
|
||||||
int error = omv_csi_set_auto_whitebal(enable, rgb_gain_db[0], rgb_gain_db[1], rgb_gain_db[2]);
|
int error = omv_csi_set_auto_whitebal(csi, enable, rgb_gain_db[0], rgb_gain_db[1], rgb_gain_db[2]);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
@ -536,7 +571,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_whitebal_obj, 1, py_omv_cs
|
|||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_rgb_gain_db() {
|
static mp_obj_t py_omv_csi_get_rgb_gain_db() {
|
||||||
float r_gain_db = 0.0, g_gain_db = 0.0, b_gain_db = 0.0;
|
float r_gain_db = 0.0, g_gain_db = 0.0, b_gain_db = 0.0;
|
||||||
int error = omv_csi_get_rgb_gain_db(&r_gain_db, &g_gain_db, &b_gain_db);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_get_rgb_gain_db(csi, &r_gain_db, &g_gain_db, &b_gain_db);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -558,18 +594,20 @@ static mp_obj_t py_omv_csi_set_auto_blc(size_t n_args, const mp_obj_t *pos_args,
|
|||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
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);
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int enable = args[ARG_enable].u_int;
|
int enable = args[ARG_enable].u_int;
|
||||||
int regs[csi.blc_size];
|
int regs[csi->blc_size];
|
||||||
bool regs_present = args[ARG_regs].u_obj != mp_const_none;
|
bool regs_present = args[ARG_regs].u_obj != mp_const_none;
|
||||||
|
|
||||||
if (regs_present) {
|
if (regs_present) {
|
||||||
mp_obj_t *arg_array;
|
mp_obj_t *arg_array;
|
||||||
mp_obj_get_array_fixed_n(args[ARG_regs].u_obj, csi.blc_size, &arg_array);
|
mp_obj_get_array_fixed_n(args[ARG_regs].u_obj, csi->blc_size, &arg_array);
|
||||||
for (uint32_t i = 0; i < csi.blc_size; i++) {
|
for (uint32_t i = 0; i < csi->blc_size; i++) {
|
||||||
regs[i] = mp_obj_get_int(arg_array[i]);
|
regs[i] = mp_obj_get_int(arg_array[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int error = omv_csi_set_auto_blc(enable, regs_present ? regs : NULL);
|
int error = omv_csi_set_auto_blc(csi, enable, regs_present ? regs : NULL);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
if (error != OMV_CSI_ERROR_CTL_UNSUPPORTED) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
@ -581,14 +619,16 @@ static mp_obj_t py_omv_csi_set_auto_blc(size_t n_args, const mp_obj_t *pos_args,
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_blc_obj, 1, py_omv_csi_set_auto_blc);
|
static MP_DEFINE_CONST_FUN_OBJ_KW(py_omv_csi_set_auto_blc_obj, 1, py_omv_csi_set_auto_blc);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_blc_regs() {
|
static mp_obj_t py_omv_csi_get_blc_regs() {
|
||||||
int regs[csi.blc_size];
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int error = omv_csi_get_blc_regs(regs);
|
int regs[csi->blc_size];
|
||||||
|
|
||||||
|
int error = omv_csi_get_blc_regs(csi, regs);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_list_t *l = mp_obj_new_list(csi.blc_size, NULL);
|
mp_obj_list_t *l = mp_obj_new_list(csi->blc_size, NULL);
|
||||||
for (uint32_t i = 0; i < csi.blc_size; i++) {
|
for (uint32_t i = 0; i < csi->blc_size; i++) {
|
||||||
l->items[i] = mp_obj_new_int(regs[i]);
|
l->items[i] = mp_obj_new_int(regs[i]);
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
@ -596,7 +636,8 @@ static mp_obj_t py_omv_csi_get_blc_regs() {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_blc_regs_obj, py_omv_csi_get_blc_regs);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_blc_regs_obj, py_omv_csi_get_blc_regs);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_hmirror(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_set_hmirror(mp_obj_t enable) {
|
||||||
int error = omv_csi_set_hmirror(mp_obj_is_true(enable));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_hmirror(csi, mp_obj_is_true(enable));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -605,12 +646,14 @@ static mp_obj_t py_omv_csi_set_hmirror(mp_obj_t enable) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_hmirror_obj, py_omv_csi_set_hmirror);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_hmirror_obj, py_omv_csi_set_hmirror);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_hmirror() {
|
static mp_obj_t py_omv_csi_get_hmirror() {
|
||||||
return mp_obj_new_bool(omv_csi_get_hmirror());
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_bool(omv_csi_get_hmirror(csi));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_hmirror_obj, py_omv_csi_get_hmirror);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_hmirror_obj, py_omv_csi_get_hmirror);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_vflip(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_set_vflip(mp_obj_t enable) {
|
||||||
int error = omv_csi_set_vflip(mp_obj_is_true(enable));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_vflip(csi, mp_obj_is_true(enable));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -619,12 +662,14 @@ static mp_obj_t py_omv_csi_set_vflip(mp_obj_t enable) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_vflip_obj, py_omv_csi_set_vflip);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_vflip_obj, py_omv_csi_set_vflip);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_vflip() {
|
static mp_obj_t py_omv_csi_get_vflip() {
|
||||||
return mp_obj_new_bool(omv_csi_get_vflip());
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_bool(omv_csi_get_vflip(csi));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_vflip_obj, py_omv_csi_get_vflip);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_vflip_obj, py_omv_csi_get_vflip);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_transpose(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_set_transpose(mp_obj_t enable) {
|
||||||
int error = omv_csi_set_transpose(mp_obj_is_true(enable));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_transpose(csi, mp_obj_is_true(enable));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -633,12 +678,14 @@ static mp_obj_t py_omv_csi_set_transpose(mp_obj_t enable) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_transpose_obj, py_omv_csi_set_transpose);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_transpose_obj, py_omv_csi_set_transpose);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_transpose() {
|
static mp_obj_t py_omv_csi_get_transpose() {
|
||||||
return mp_obj_new_bool(omv_csi_get_transpose());
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_bool(omv_csi_get_transpose(csi));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_transpose_obj, py_omv_csi_get_transpose);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_transpose_obj, py_omv_csi_get_transpose);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_auto_rotation(mp_obj_t enable) {
|
static mp_obj_t py_omv_csi_set_auto_rotation(mp_obj_t enable) {
|
||||||
int error = omv_csi_set_auto_rotation(mp_obj_is_true(enable));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
int error = omv_csi_set_auto_rotation(csi, mp_obj_is_true(enable));
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -647,15 +694,16 @@ static mp_obj_t py_omv_csi_set_auto_rotation(mp_obj_t enable) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_auto_rotation_obj, py_omv_csi_set_auto_rotation);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_auto_rotation_obj, py_omv_csi_set_auto_rotation);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_auto_rotation() {
|
static mp_obj_t py_omv_csi_get_auto_rotation() {
|
||||||
return mp_obj_new_bool(omv_csi_get_auto_rotation());
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_bool(omv_csi_get_auto_rotation(csi));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_auto_rotation_obj, py_omv_csi_get_auto_rotation);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_auto_rotation_obj, py_omv_csi_get_auto_rotation);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_framebuffers(mp_obj_t count) {
|
static mp_obj_t py_omv_csi_set_framebuffers(mp_obj_t count) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
mp_int_t c = mp_obj_get_int(count);
|
mp_int_t c = mp_obj_get_int(count);
|
||||||
framebuffer_t *fb = framebuffer_get(0);
|
|
||||||
|
|
||||||
if (fb->n_buffers == c) {
|
if (c == csi->fb->n_buffers) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,7 +711,7 @@ static mp_obj_t py_omv_csi_set_framebuffers(mp_obj_t count) {
|
|||||||
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_ARGUMENT);
|
omv_csi_raise_error(OMV_CSI_ERROR_INVALID_ARGUMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int error = omv_csi_set_framebuffers(c);
|
int error = omv_csi_set_framebuffers(csi, c);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
omv_csi_raise_error(error);
|
omv_csi_raise_error(error);
|
||||||
}
|
}
|
||||||
@ -673,33 +721,36 @@ static mp_obj_t py_omv_csi_set_framebuffers(mp_obj_t count) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framebuffers_obj, py_omv_csi_set_framebuffers);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_framebuffers_obj, py_omv_csi_set_framebuffers);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_framebuffers() {
|
static mp_obj_t py_omv_csi_get_framebuffers() {
|
||||||
framebuffer_t *fb = framebuffer_get(0);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
return mp_obj_new_int(fb->n_buffers);
|
return mp_obj_new_int(csi->fb->n_buffers);
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framebuffers_obj, py_omv_csi_get_framebuffers);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_framebuffers_obj, py_omv_csi_get_framebuffers);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_disable_delays(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t py_omv_csi_disable_delays(size_t n_args, const mp_obj_t *args) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
if (!n_args) {
|
if (!n_args) {
|
||||||
return mp_obj_new_bool(csi.disable_delays);
|
return mp_obj_new_bool(csi->disable_delays);
|
||||||
}
|
}
|
||||||
|
|
||||||
csi.disable_delays = mp_obj_get_int(args[0]);
|
csi->disable_delays = mp_obj_get_int(args[0]);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_disable_delays_obj, 0, 1, py_omv_csi_disable_delays);
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_disable_delays_obj, 0, 1, py_omv_csi_disable_delays);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_disable_full_flush(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t py_omv_csi_disable_full_flush(size_t n_args, const mp_obj_t *args) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
if (!n_args) {
|
if (!n_args) {
|
||||||
return mp_obj_new_bool(csi.disable_full_flush);
|
return mp_obj_new_bool(csi->disable_full_flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
csi.disable_full_flush = mp_obj_get_int(args[0]);
|
csi->disable_full_flush = mp_obj_get_int(args[0]);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_disable_full_flush_obj, 0, 1, py_omv_csi_disable_full_flush);
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_disable_full_flush_obj, 0, 1, py_omv_csi_disable_full_flush);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_special_effect(mp_obj_t sde) {
|
static mp_obj_t py_omv_csi_set_special_effect(mp_obj_t sde) {
|
||||||
if (omv_csi_set_special_effect(mp_obj_get_int(sde)) != 0) {
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_special_effect(csi, mp_obj_get_int(sde)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
@ -707,7 +758,8 @@ static mp_obj_t py_omv_csi_set_special_effect(mp_obj_t sde) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_special_effect_obj, py_omv_csi_set_special_effect);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_special_effect_obj, py_omv_csi_set_special_effect);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp_obj_t coef) {
|
static mp_obj_t py_omv_csi_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp_obj_t coef) {
|
||||||
if (omv_csi_set_lens_correction(mp_obj_is_true(enable),
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
if (omv_csi_set_lens_correction(csi, mp_obj_is_true(enable),
|
||||||
mp_obj_get_int(radi), mp_obj_get_int(coef)) != 0) {
|
mp_obj_get_int(radi), mp_obj_get_int(coef)) != 0) {
|
||||||
return mp_const_false;
|
return mp_const_false;
|
||||||
}
|
}
|
||||||
@ -715,45 +767,58 @@ static mp_obj_t py_omv_csi_set_lens_correction(mp_obj_t enable, mp_obj_t radi, m
|
|||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_3(py_omv_csi_set_lens_correction_obj, py_omv_csi_set_lens_correction);
|
static MP_DEFINE_CONST_FUN_OBJ_3(py_omv_csi_set_lens_correction_obj, py_omv_csi_set_lens_correction);
|
||||||
|
|
||||||
static void omv_csi_vsync_callback(uint32_t vsync) {
|
static void omv_csi_vsync_callback(void *data) {
|
||||||
if (mp_obj_is_callable(vsync_callback)) {
|
if (mp_obj_is_callable(vsync_callback)) {
|
||||||
mp_call_function_1(vsync_callback, mp_obj_new_int(vsync));
|
uint32_t vsync_state = 0;
|
||||||
|
#ifdef OMV_CSI_VSYNC_PIN
|
||||||
|
vsync_state = omv_gpio_read(OMV_CSI_VSYNC_PIN);
|
||||||
|
#endif
|
||||||
|
mp_call_function_1(vsync_callback, mp_obj_new_int(vsync_state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_vsync_callback(mp_obj_t vsync_callback_obj) {
|
static mp_obj_t py_omv_csi_set_vsync_callback(mp_obj_t vsync_callback_obj) {
|
||||||
|
omv_csi_cb_t cb;
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
if (!mp_obj_is_callable(vsync_callback_obj)) {
|
if (!mp_obj_is_callable(vsync_callback_obj)) {
|
||||||
vsync_callback = mp_const_none;
|
vsync_callback = mp_const_none;
|
||||||
omv_csi_set_vsync_callback(NULL);
|
cb = (omv_csi_cb_t) { NULL, NULL };
|
||||||
} else {
|
} else {
|
||||||
vsync_callback = vsync_callback_obj;
|
vsync_callback = vsync_callback_obj;
|
||||||
omv_csi_set_vsync_callback(omv_csi_vsync_callback);
|
cb = (omv_csi_cb_t) { omv_csi_vsync_callback, NULL };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
omv_csi_set_vsync_callback(csi, cb);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_vsync_callback_obj, py_omv_csi_set_vsync_callback);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_vsync_callback_obj, py_omv_csi_set_vsync_callback);
|
||||||
|
|
||||||
static void omv_csi_frame_callback() {
|
static void omv_csi_frame_callback(void *data) {
|
||||||
if (mp_obj_is_callable(frame_callback)) {
|
if (mp_obj_is_callable(frame_callback)) {
|
||||||
mp_call_function_0(frame_callback);
|
mp_call_function_0(frame_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_frame_callback(mp_obj_t frame_callback_obj) {
|
static mp_obj_t py_omv_csi_set_frame_callback(mp_obj_t frame_callback_obj) {
|
||||||
|
omv_csi_cb_t cb;
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
if (!mp_obj_is_callable(frame_callback_obj)) {
|
if (!mp_obj_is_callable(frame_callback_obj)) {
|
||||||
frame_callback = mp_const_none;
|
frame_callback = mp_const_none;
|
||||||
omv_csi_set_frame_callback(NULL);
|
cb = (omv_csi_cb_t) { NULL, NULL };
|
||||||
} else {
|
} else {
|
||||||
frame_callback = frame_callback_obj;
|
frame_callback = frame_callback_obj;
|
||||||
omv_csi_set_frame_callback(omv_csi_frame_callback);
|
cb = (omv_csi_cb_t) { omv_csi_frame_callback, NULL };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
omv_csi_set_frame_callback(csi, cb);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_frame_callback_obj, py_omv_csi_set_frame_callback);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_frame_callback_obj, py_omv_csi_set_frame_callback);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
mp_obj_t ret_obj = mp_const_none;
|
mp_obj_t ret_obj = mp_const_none;
|
||||||
int request = mp_obj_get_int(args[0]);
|
int request = mp_obj_get_int(args[0]);
|
||||||
int error = OMV_CSI_ERROR_INVALID_ARGUMENT;
|
int error = OMV_CSI_ERROR_INVALID_ARGUMENT;
|
||||||
@ -781,14 +846,14 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
MP_ERROR_TEXT("The tuple/list must either be (x, y, w, h) or (w, h)"));
|
MP_ERROR_TEXT("The tuple/list must either be (x, y, w, h) or (w, h)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
error = omv_csi_ioctl(request, x, y, w, h);
|
error = omv_csi_ioctl(csi, request, x, y, w, h);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_GET_READOUT_WINDOW: {
|
case OMV_CSI_IOCTL_GET_READOUT_WINDOW: {
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
error = omv_csi_ioctl(request, &x, &y, &w, &h);
|
error = omv_csi_ioctl(csi, request, &x, &y, &w, &h);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(x),
|
ret_obj = mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(x),
|
||||||
mp_obj_new_int(y),
|
mp_obj_new_int(y),
|
||||||
@ -802,7 +867,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
case OMV_CSI_IOCTL_SET_FOV_WIDE:
|
case OMV_CSI_IOCTL_SET_FOV_WIDE:
|
||||||
case OMV_CSI_IOCTL_SET_NIGHT_MODE: {
|
case OMV_CSI_IOCTL_SET_NIGHT_MODE: {
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -811,7 +876,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
case OMV_CSI_IOCTL_GET_FOV_WIDE:
|
case OMV_CSI_IOCTL_GET_FOV_WIDE:
|
||||||
case OMV_CSI_IOCTL_GET_NIGHT_MODE: {
|
case OMV_CSI_IOCTL_GET_NIGHT_MODE: {
|
||||||
int enabled;
|
int enabled;
|
||||||
error = omv_csi_ioctl(request, &enabled);
|
error = omv_csi_ioctl(csi, request, &enabled);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_bool(enabled);
|
ret_obj = mp_obj_new_bool(enabled);
|
||||||
}
|
}
|
||||||
@ -822,18 +887,18 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
case OMV_CSI_IOCTL_TRIGGER_AUTO_FOCUS:
|
case OMV_CSI_IOCTL_TRIGGER_AUTO_FOCUS:
|
||||||
case OMV_CSI_IOCTL_PAUSE_AUTO_FOCUS:
|
case OMV_CSI_IOCTL_PAUSE_AUTO_FOCUS:
|
||||||
case OMV_CSI_IOCTL_RESET_AUTO_FOCUS: {
|
case OMV_CSI_IOCTL_RESET_AUTO_FOCUS: {
|
||||||
error = omv_csi_ioctl(request);
|
error = omv_csi_ioctl(csi, request);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OMV_CSI_IOCTL_WAIT_ON_AUTO_FOCUS: {
|
case OMV_CSI_IOCTL_WAIT_ON_AUTO_FOCUS: {
|
||||||
error = omv_csi_ioctl(request, (n_args < 2) ? 5000 : mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, (n_args < 2) ? 5000 : mp_obj_get_int(args[1]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_WIDTH: {
|
case OMV_CSI_IOCTL_LEPTON_GET_WIDTH: {
|
||||||
int width;
|
int width;
|
||||||
error = omv_csi_ioctl(request, &width);
|
error = omv_csi_ioctl(csi, request, &width);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_int(width);
|
ret_obj = mp_obj_new_int(width);
|
||||||
}
|
}
|
||||||
@ -842,7 +907,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_HEIGHT: {
|
case OMV_CSI_IOCTL_LEPTON_GET_HEIGHT: {
|
||||||
int height;
|
int height;
|
||||||
error = omv_csi_ioctl(request, &height);
|
error = omv_csi_ioctl(csi, request, &height);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_int(height);
|
ret_obj = mp_obj_new_int(height);
|
||||||
}
|
}
|
||||||
@ -851,7 +916,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_RADIOMETRY: {
|
case OMV_CSI_IOCTL_LEPTON_GET_RADIOMETRY: {
|
||||||
int radiometry;
|
int radiometry;
|
||||||
error = omv_csi_ioctl(request, &radiometry);
|
error = omv_csi_ioctl(csi, request, &radiometry);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_int(radiometry);
|
ret_obj = mp_obj_new_int(radiometry);
|
||||||
}
|
}
|
||||||
@ -860,7 +925,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_REFRESH: {
|
case OMV_CSI_IOCTL_LEPTON_GET_REFRESH: {
|
||||||
int refresh;
|
int refresh;
|
||||||
error = omv_csi_ioctl(request, &refresh);
|
error = omv_csi_ioctl(csi, request, &refresh);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_int(refresh);
|
ret_obj = mp_obj_new_int(refresh);
|
||||||
}
|
}
|
||||||
@ -869,7 +934,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_RESOLUTION: {
|
case OMV_CSI_IOCTL_LEPTON_GET_RESOLUTION: {
|
||||||
int resolution;
|
int resolution;
|
||||||
error = omv_csi_ioctl(request, &resolution);
|
error = omv_csi_ioctl(csi, request, &resolution);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_int(resolution);
|
ret_obj = mp_obj_new_int(resolution);
|
||||||
}
|
}
|
||||||
@ -878,7 +943,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_RUN_COMMAND: {
|
case OMV_CSI_IOCTL_LEPTON_RUN_COMMAND: {
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -889,7 +954,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
int command = mp_obj_get_int(args[1]);
|
int command = mp_obj_get_int(args[1]);
|
||||||
uint16_t *data = (uint16_t *) mp_obj_str_get_data(args[2], &data_len);
|
uint16_t *data = (uint16_t *) mp_obj_str_get_data(args[2], &data_len);
|
||||||
PY_ASSERT_TRUE_MSG(data_len > 0, "0 bytes transferred!");
|
PY_ASSERT_TRUE_MSG(data_len > 0, "0 bytes transferred!");
|
||||||
error = omv_csi_ioctl(request, command, data, data_len / sizeof(uint16_t));
|
error = omv_csi_ioctl(csi, request, command, data, data_len / sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -900,7 +965,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
size_t data_len = mp_obj_get_int(args[2]);
|
size_t data_len = mp_obj_get_int(args[2]);
|
||||||
PY_ASSERT_TRUE_MSG(data_len > 0, "0 bytes transferred!");
|
PY_ASSERT_TRUE_MSG(data_len > 0, "0 bytes transferred!");
|
||||||
uint16_t *data = xalloc(data_len * sizeof(uint16_t));
|
uint16_t *data = xalloc(data_len * sizeof(uint16_t));
|
||||||
error = omv_csi_ioctl(request, command, data, data_len);
|
error = omv_csi_ioctl(csi, request, command, data, data_len);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_bytearray_by_ref(data_len * sizeof(uint16_t), data);
|
ret_obj = mp_obj_new_bytearray_by_ref(data_len * sizeof(uint16_t), data);
|
||||||
}
|
}
|
||||||
@ -911,7 +976,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
case OMV_CSI_IOCTL_LEPTON_GET_FPA_TEMP:
|
case OMV_CSI_IOCTL_LEPTON_GET_FPA_TEMP:
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_AUX_TEMP: {
|
case OMV_CSI_IOCTL_LEPTON_GET_AUX_TEMP: {
|
||||||
int temp;
|
int temp;
|
||||||
error = omv_csi_ioctl(request, &temp);
|
error = omv_csi_ioctl(csi, request, &temp);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_float((((float) temp) / 100) - 273.15f);
|
ret_obj = mp_obj_new_float((((float) temp) / 100) - 273.15f);
|
||||||
}
|
}
|
||||||
@ -921,13 +986,13 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
case OMV_CSI_IOCTL_LEPTON_SET_MODE:
|
case OMV_CSI_IOCTL_LEPTON_SET_MODE:
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
int high_temp = (n_args == 2) ? false : mp_obj_get_int(args[2]);
|
int high_temp = (n_args == 2) ? false : mp_obj_get_int(args[2]);
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]), high_temp);
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]), high_temp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_MODE: {
|
case OMV_CSI_IOCTL_LEPTON_GET_MODE: {
|
||||||
int enabled, high_temp;
|
int enabled, high_temp;
|
||||||
error = omv_csi_ioctl(request, &enabled, &high_temp);
|
error = omv_csi_ioctl(csi, request, &enabled, &high_temp);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_bool(enabled), mp_obj_new_bool(high_temp)});
|
ret_obj = mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_bool(enabled), mp_obj_new_bool(high_temp)});
|
||||||
}
|
}
|
||||||
@ -939,13 +1004,13 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
// GCC will not let us pass floats to ... so we have to pass float pointers instead.
|
// GCC will not let us pass floats to ... so we have to pass float pointers instead.
|
||||||
float min = mp_obj_get_float(args[1]);
|
float min = mp_obj_get_float(args[1]);
|
||||||
float max = mp_obj_get_float(args[2]);
|
float max = mp_obj_get_float(args[2]);
|
||||||
error = omv_csi_ioctl(request, &min, &max);
|
error = omv_csi_ioctl(csi, request, &min, &max);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_LEPTON_GET_RANGE: {
|
case OMV_CSI_IOCTL_LEPTON_GET_RANGE: {
|
||||||
float min, max;
|
float min, max;
|
||||||
error = omv_csi_ioctl(request, &min, &max);
|
error = omv_csi_ioctl(csi, request, &min, &max);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_float(min), mp_obj_new_float(max)});
|
ret_obj = mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_float(min), mp_obj_new_float(max)});
|
||||||
}
|
}
|
||||||
@ -955,7 +1020,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
#if (OMV_HM01B0_ENABLE == 1)
|
#if (OMV_HM01B0_ENABLE == 1)
|
||||||
case OMV_CSI_IOCTL_HIMAX_MD_ENABLE: {
|
case OMV_CSI_IOCTL_HIMAX_MD_ENABLE: {
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -982,26 +1047,26 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
MP_ERROR_TEXT("The tuple/list must either be (x, y, w, h) or (w, h)"));
|
MP_ERROR_TEXT("The tuple/list must either be (x, y, w, h) or (w, h)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
error = omv_csi_ioctl(request, x, y, w, h);
|
error = omv_csi_ioctl(csi, request, x, y, w, h);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_HIMAX_MD_THRESHOLD: {
|
case OMV_CSI_IOCTL_HIMAX_MD_THRESHOLD: {
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_HIMAX_MD_CLEAR: {
|
case OMV_CSI_IOCTL_HIMAX_MD_CLEAR: {
|
||||||
error = omv_csi_ioctl(request);
|
error = omv_csi_ioctl(csi, request);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OMV_CSI_IOCTL_HIMAX_OSC_ENABLE: {
|
case OMV_CSI_IOCTL_HIMAX_OSC_ENABLE: {
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1009,7 +1074,7 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
case OMV_CSI_IOCTL_GET_RGB_STATS: {
|
case OMV_CSI_IOCTL_GET_RGB_STATS: {
|
||||||
uint32_t r, gb, gr, b;
|
uint32_t r, gb, gr, b;
|
||||||
error = omv_csi_ioctl(request, &r, &gb, &gr, &b);
|
error = omv_csi_ioctl(csi, request, &r, &gb, &gr, &b);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ret_obj = mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(r),
|
ret_obj = mp_obj_new_tuple(4, (mp_obj_t []) {mp_obj_new_int(r),
|
||||||
mp_obj_new_int(gb),
|
mp_obj_new_int(gb),
|
||||||
@ -1022,21 +1087,21 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
#if (OMV_GENX320_ENABLE == 1)
|
#if (OMV_GENX320_ENABLE == 1)
|
||||||
case OMV_CSI_IOCTL_GENX320_SET_BIASES: {
|
case OMV_CSI_IOCTL_GENX320_SET_BIASES: {
|
||||||
if (n_args == 2) {
|
if (n_args == 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OMV_CSI_IOCTL_GENX320_SET_BIAS: {
|
case OMV_CSI_IOCTL_GENX320_SET_BIAS: {
|
||||||
if (n_args == 3) {
|
if (n_args == 3) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OMV_CSI_IOCTL_GENX320_SET_AFK: {
|
case OMV_CSI_IOCTL_GENX320_SET_AFK: {
|
||||||
if (n_args == 2) {
|
if (n_args == 2) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]));
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]));
|
||||||
} else if (n_args == 4) {
|
} else if (n_args == 4) {
|
||||||
error = omv_csi_ioctl(request, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]),
|
error = omv_csi_ioctl(csi, request, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]),
|
||||||
mp_obj_get_int(args[3]));
|
mp_obj_get_int(args[3]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1058,25 +1123,26 @@ static mp_obj_t py_omv_csi_ioctl(size_t n_args, const mp_obj_t *args) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_ioctl_obj, 1, 5, py_omv_csi_ioctl);
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_omv_csi_ioctl_obj, 1, 5, py_omv_csi_ioctl);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_set_color_palette(mp_obj_t palette_obj) {
|
static mp_obj_t py_omv_csi_set_color_palette(mp_obj_t palette_obj) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
int palette = mp_obj_get_int(palette_obj);
|
int palette = mp_obj_get_int(palette_obj);
|
||||||
switch (palette) {
|
switch (palette) {
|
||||||
case COLOR_PALETTE_RAINBOW:
|
case COLOR_PALETTE_RAINBOW:
|
||||||
omv_csi_set_color_palette(rainbow_table);
|
omv_csi_set_color_palette(csi, rainbow_table);
|
||||||
break;
|
break;
|
||||||
case COLOR_PALETTE_IRONBOW:
|
case COLOR_PALETTE_IRONBOW:
|
||||||
omv_csi_set_color_palette(ironbow_table);
|
omv_csi_set_color_palette(csi, ironbow_table);
|
||||||
break;
|
break;
|
||||||
#if (MICROPY_PY_TOF == 1)
|
#if (MICROPY_PY_TOF == 1)
|
||||||
case COLOR_PALETTE_DEPTH:
|
case COLOR_PALETTE_DEPTH:
|
||||||
omv_csi_set_color_palette(depth_table);
|
omv_csi_set_color_palette(csi, depth_table);
|
||||||
break;
|
break;
|
||||||
#endif // MICROPY_PY_TOF == 1
|
#endif // MICROPY_PY_TOF == 1
|
||||||
#if (OMV_GENX320_ENABLE == 1)
|
#if (OMV_GENX320_ENABLE == 1)
|
||||||
case COLOR_PALETTE_EVT_DARK:
|
case COLOR_PALETTE_EVT_DARK:
|
||||||
omv_csi_set_color_palette(evt_dark_table);
|
omv_csi_set_color_palette(csi, evt_dark_table);
|
||||||
break;
|
break;
|
||||||
case COLOR_PALETTE_EVT_LIGHT:
|
case COLOR_PALETTE_EVT_LIGHT:
|
||||||
omv_csi_set_color_palette(evt_light_table);
|
omv_csi_set_color_palette(csi, evt_light_table);
|
||||||
break;
|
break;
|
||||||
#endif // OMV_GENX320_ENABLE == 1
|
#endif // OMV_GENX320_ENABLE == 1
|
||||||
default:
|
default:
|
||||||
@ -1088,7 +1154,8 @@ static mp_obj_t py_omv_csi_set_color_palette(mp_obj_t palette_obj) {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_color_palette_obj, py_omv_csi_set_color_palette);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_set_color_palette_obj, py_omv_csi_set_color_palette);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_get_color_palette() {
|
static mp_obj_t py_omv_csi_get_color_palette() {
|
||||||
const uint16_t *palette = omv_csi_get_color_palette();
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
const uint16_t *palette = omv_csi_get_color_palette(csi);
|
||||||
if (palette == rainbow_table) {
|
if (palette == rainbow_table) {
|
||||||
return mp_obj_new_int(COLOR_PALETTE_RAINBOW);
|
return mp_obj_new_int(COLOR_PALETTE_RAINBOW);
|
||||||
} else if (palette == ironbow_table) {
|
} else if (palette == ironbow_table) {
|
||||||
@ -1109,13 +1176,15 @@ static mp_obj_t py_omv_csi_get_color_palette() {
|
|||||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_color_palette_obj, py_omv_csi_get_color_palette);
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_csi_get_color_palette_obj, py_omv_csi_get_color_palette);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_write_reg(mp_obj_t addr, mp_obj_t val) {
|
static mp_obj_t py_omv_csi_write_reg(mp_obj_t addr, mp_obj_t val) {
|
||||||
omv_csi_write_reg(mp_obj_get_int(addr), mp_obj_get_int(val));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
omv_csi_write_reg(csi, mp_obj_get_int(addr), mp_obj_get_int(val));
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_2(py_omv_csi_write_reg_obj, py_omv_csi_write_reg);
|
static MP_DEFINE_CONST_FUN_OBJ_2(py_omv_csi_write_reg_obj, py_omv_csi_write_reg);
|
||||||
|
|
||||||
static mp_obj_t py_omv_csi_read_reg(mp_obj_t addr) {
|
static mp_obj_t py_omv_csi_read_reg(mp_obj_t addr) {
|
||||||
return mp_obj_new_int(omv_csi_read_reg(mp_obj_get_int(addr)));
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
return mp_obj_new_int(omv_csi_read_reg(csi, mp_obj_get_int(addr)));
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_read_reg_obj, py_omv_csi_read_reg);
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_omv_csi_read_reg_obj, py_omv_csi_read_reg);
|
||||||
|
|
||||||
@ -1323,6 +1392,5 @@ const mp_obj_module_t omv_csi_module = {
|
|||||||
.globals = (mp_obj_t) &globals_dict,
|
.globals = (mp_obj_t) &globals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_REGISTER_MODULE(MP_QSTR_csi, omv_csi_module);
|
|
||||||
MP_REGISTER_MODULE(MP_QSTR_sensor, omv_csi_module);
|
MP_REGISTER_MODULE(MP_QSTR_sensor, omv_csi_module);
|
||||||
#endif // MICROPY_PY_CSI
|
#endif // MICROPY_PY_CSI
|
||||||
|
1511
modules/py_csi_ng.c
Normal file
1511
modules/py_csi_ng.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -558,11 +558,14 @@ void py_helper_update_framebuffer(image_t *img) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void py_helper_set_to_framebuffer(image_t *img) {
|
void py_helper_set_to_framebuffer(image_t *img) {
|
||||||
|
#if MICROPY_PY_CSI
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
|
omv_csi_set_framebuffers(csi, 1);
|
||||||
|
#else
|
||||||
framebuffer_t *fb = framebuffer_get(0);
|
framebuffer_t *fb = framebuffer_get(0);
|
||||||
|
|
||||||
#if MICROPY_PY_CSI
|
|
||||||
omv_csi_set_framebuffers(1);
|
|
||||||
#else
|
|
||||||
framebuffer_set_buffers(fb, 1);
|
framebuffer_set_buffers(fb, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/alif/tinyusb_port
|
|||||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/alif/lwip_inc
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/alif/lwip_inc
|
||||||
|
|
||||||
MPY_CFLAGS += -DMICROPY_PY_CSI=$(MICROPY_PY_CSI)
|
MPY_CFLAGS += -DMICROPY_PY_CSI=$(MICROPY_PY_CSI)
|
||||||
|
MPY_CFLAGS += -DMICROPY_PY_CSI_NG=$(MICROPY_PY_CSI_NG)
|
||||||
MPY_CFLAGS += -DMICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
MPY_CFLAGS += -DMICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
||||||
MPY_CFLAGS += -DMICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
MPY_CFLAGS += -DMICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
||||||
MPY_CFLAGS += -DMICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
MPY_CFLAGS += -DMICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
||||||
@ -126,6 +127,7 @@ MPY_MKARGS += MICROPY_FLOAT_IMPL=float
|
|||||||
MPY_MKARGS += ALIF_DFP_REL_HERE=$(TOP_DIR)/$(HAL_DIR)
|
MPY_MKARGS += ALIF_DFP_REL_HERE=$(TOP_DIR)/$(HAL_DIR)
|
||||||
MPY_MKARGS += CMSIS_DIR=$(TOP_DIR)/$(HAL_DIR)/cmsis/inc
|
MPY_MKARGS += CMSIS_DIR=$(TOP_DIR)/$(HAL_DIR)/cmsis/inc
|
||||||
MPY_MKARGS += MICROPY_PY_CSI=$(MICROPY_PY_CSI)
|
MPY_MKARGS += MICROPY_PY_CSI=$(MICROPY_PY_CSI)
|
||||||
|
MPY_MKARGS += MICROPY_PY_CSI_NG=$(MICROPY_PY_CSI_NG)
|
||||||
MPY_MKARGS += MICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
MPY_MKARGS += MICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
||||||
MPY_MKARGS += MICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
MPY_MKARGS += MICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
||||||
MPY_MKARGS += MICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
MPY_MKARGS += MICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
||||||
|
@ -71,33 +71,9 @@
|
|||||||
CAM_INTR_OUTFIFO_OVERRUN | \
|
CAM_INTR_OUTFIFO_OVERRUN | \
|
||||||
CAM_INTR_BRESP_ERR)
|
CAM_INTR_BRESP_ERR)
|
||||||
|
|
||||||
static CPI_Type *cpi_get_base_addr(omv_csi_t *csi) {
|
int alif_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
return ((CPI_Type *) CPI_BASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void omv_csi_init0() {
|
|
||||||
omv_csi_abort(&csi, true, false);
|
|
||||||
|
|
||||||
// Re-init I2C to reset the bus state after soft reset, which
|
|
||||||
// could have interrupted the bus in the middle of a transfer.
|
|
||||||
if (csi.i2c->initialized) {
|
|
||||||
// Reinitialize the bus using the last used id and speed.
|
|
||||||
// TODO: Causes Alif's I3C to lock up.
|
|
||||||
//omv_i2c_init(csi.i2c, csi.i2c->id, csi.i2c->speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
csi.disable_delays = false;
|
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
|
||||||
if (config == OMV_CSI_CONFIG_INIT) {
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
CPI_Type *cpi = cpi_get_base_addr(&csi);
|
CPI_Type *cpi = csi->base;
|
||||||
|
|
||||||
// Configure the FIFO.
|
// Configure the FIFO.
|
||||||
cpi->CAM_FIFO_CTRL &= ~CAM_FIFO_CTRL_RD_WMARK_Msk;
|
cpi->CAM_FIFO_CTRL &= ~CAM_FIFO_CTRL_RD_WMARK_Msk;
|
||||||
@ -113,9 +89,9 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
cpi->CAM_CFG |= (CPI_VSYNC_WAIT_DISABLE << CAM_CFG_VSYNC_WAIT_Pos);
|
cpi->CAM_CFG |= (CPI_VSYNC_WAIT_DISABLE << CAM_CFG_VSYNC_WAIT_Pos);
|
||||||
|
|
||||||
// Set VSYNC, HSYNC and PIXCLK polarities.
|
// Set VSYNC, HSYNC and PIXCLK polarities.
|
||||||
cpi->CAM_CFG |= (csi.vsync_pol << CAM_CFG_VSYNC_POL_Pos);
|
cpi->CAM_CFG |= (csi->vsync_pol << CAM_CFG_VSYNC_POL_Pos);
|
||||||
cpi->CAM_CFG |= (csi.hsync_pol << CAM_CFG_HSYNC_POL_Pos);
|
cpi->CAM_CFG |= (csi->hsync_pol << CAM_CFG_HSYNC_POL_Pos);
|
||||||
cpi->CAM_CFG |= (!csi.pixck_pol << CAM_CFG_PXCLK_POL_Pos);
|
cpi->CAM_CFG |= (!csi->pixck_pol << CAM_CFG_PXCLK_POL_Pos);
|
||||||
|
|
||||||
// Configure the data bus width, mode, endianness.
|
// Configure the data bus width, mode, endianness.
|
||||||
cpi->CAM_CFG |= (CPI_ROW_ROUNDUP_DISABLE << CAM_CFG_RW_ROUNDUP_Pos);
|
cpi->CAM_CFG |= (CPI_ROW_ROUNDUP_DISABLE << CAM_CFG_RW_ROUNDUP_Pos);
|
||||||
@ -133,25 +109,16 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
int alif_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
CPI_Type *cpi = cpi_get_base_addr(csi);
|
CPI_Type *cpi = csi->base;
|
||||||
|
|
||||||
|
// Stop CPI
|
||||||
cpi->CAM_CTRL = 0;
|
cpi->CAM_CTRL = 0;
|
||||||
|
|
||||||
|
// Disable IRQs.
|
||||||
NVIC_DisableIRQ(CAM_IRQ_IRQn);
|
NVIC_DisableIRQ(CAM_IRQ_IRQn);
|
||||||
cpi_disable_interrupt(cpi, CPI_IRQ_FLAGS);
|
cpi_disable_interrupt(cpi, CPI_IRQ_FLAGS);
|
||||||
cpi_irq_handler_clear_intr_status(cpi, CPI_IRQ_FLAGS);
|
cpi_irq_handler_clear_intr_status(cpi, CPI_IRQ_FLAGS);
|
||||||
|
|
||||||
csi->first_line = false;
|
|
||||||
csi->drop_frame = false;
|
|
||||||
csi->last_frame_ms = 0;
|
|
||||||
csi->last_frame_ms_valid = false;
|
|
||||||
|
|
||||||
if (csi->fb) {
|
|
||||||
if (fifo_flush) {
|
|
||||||
framebuffer_flush_buffers(csi->fb, true);
|
|
||||||
} else if (!csi->disable_full_flush) {
|
|
||||||
framebuffer_flush_buffers(csi->fb, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,26 +146,27 @@ uint32_t omv_csi_get_clk_frequency() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint32_t line_size_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
uint32_t line_size_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
||||||
|
|
||||||
// Offset the pixels buffer for debayering.
|
// Offset the pixels buffer for debayering.
|
||||||
if (csi->raw_output && csi->pixformat == PIXFORMAT_RGB565) {
|
if (csi->raw_output && csi->pixformat == PIXFORMAT_RGB565) {
|
||||||
offset += line_size_bytes * resolution[csi->framesize][1];
|
offset += line_size_bytes * resolution[csi->framesize][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
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;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
static uint32_t frames = 0;
|
static uint32_t frames = 0;
|
||||||
static uint32_t r_stat, gb_stat, gr_stat, b_stat;
|
static uint32_t r_stat, gb_stat, gr_stat, b_stat;
|
||||||
|
|
||||||
CPI_Type *cpi = cpi_get_base_addr(csi);
|
|
||||||
|
|
||||||
if (csi->pixformat == PIXFORMAT_INVALID) {
|
if (csi->pixformat == PIXFORMAT_INVALID) {
|
||||||
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
||||||
}
|
}
|
||||||
@ -207,7 +175,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (omv_csi_check_framebuffer_size() != 0) {
|
if (omv_csi_check_framebuffer_size(csi) != 0) {
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +188,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
// Reconfigure and restart the CSI transfer if it's not running.
|
// Reconfigure and restart the CSI transfer if it's not running.
|
||||||
if (!(cpi->CAM_CTRL & CAM_CTRL_BUSY)) {
|
if (!(cpi->CAM_CTRL & CAM_CTRL_BUSY)) {
|
||||||
framebuffer_setup_buffers(fb);
|
framebuffer_setup_buffers(fb);
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint32_t line_size_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
uint32_t line_size_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
||||||
|
|
||||||
// Error out if the transfer size is not compatible with DMA transfer restrictions.
|
// Error out if the transfer size is not compatible with DMA transfer restrictions.
|
||||||
@ -353,7 +321,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Crop first to reduce the frame size before debayering.
|
// Crop first to reduce the frame size before debayering.
|
||||||
if (omv_csi_get_cropped()) {
|
if (omv_csi_get_cropped(csi)) {
|
||||||
image_t src_cimage = *dst_image;
|
image_t src_cimage = *dst_image;
|
||||||
image_t dst_cimage = *dst_image;
|
image_t dst_cimage = *dst_image;
|
||||||
|
|
||||||
@ -387,7 +355,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
|
|
||||||
// Update AWB stats every n frames.
|
// Update AWB stats every n frames.
|
||||||
if ((frames++ % 100) == 0) {
|
if ((frames++ % 100) == 0) {
|
||||||
omv_csi_ioctl(OMV_CSI_IOCTL_GET_RGB_STATS, &r_stat, &gb_stat, &gr_stat, &b_stat);
|
omv_csi_ioctl(csi, OMV_CSI_IOCTL_GET_RGB_STATS, &r_stat, &gb_stat, &gr_stat, &b_stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debayer frame.
|
// Debayer frame.
|
||||||
@ -398,9 +366,10 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
|||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int init_ret = 0;
|
||||||
CPI_Type *cpi = cpi_get_base_addr(&csi);
|
static omv_i2c_t i2c;
|
||||||
|
CPI_Type *base = ((CPI_Type *) CPI_BASE);
|
||||||
|
|
||||||
alif_hal_csi_init(cpi, 0);
|
alif_hal_csi_init(base, 0);
|
||||||
|
|
||||||
#if defined(OMV_CSI_POWER_PIN)
|
#if defined(OMV_CSI_POWER_PIN)
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
||||||
@ -410,17 +379,20 @@ int omv_csi_init() {
|
|||||||
omv_gpio_write(OMV_CSI_RESET_PIN, 0);
|
omv_gpio_write(OMV_CSI_RESET_PIN, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->base = base;
|
||||||
csi.i2c = &csi_i2c;
|
csi->abort = alif_csi_abort;
|
||||||
|
csi->config = alif_csi_config;
|
||||||
// Set default snapshot function.
|
csi->snapshot = alif_csi_snapshot;
|
||||||
csi.snapshot = omv_csi_snapshot;
|
csi->color_palette = rainbow_table;
|
||||||
|
}
|
||||||
|
|
||||||
// Configure the CSI external clock.
|
// Configure the CSI external clock.
|
||||||
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
@ -428,36 +400,37 @@ int omv_csi_init() {
|
|||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the camera bus.
|
||||||
|
omv_i2c_init(&i2c, OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED);
|
||||||
|
|
||||||
// Detect and initialize the image csi.
|
// Detect and initialize the image csi.
|
||||||
if ((init_ret = omv_csi_probe_init(OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED)) != 0) {
|
if ((init_ret = omv_csi_probe(&i2c)) != 0) {
|
||||||
// csi probe/init failed.
|
// csi probe/init failed.
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the CSI interface.
|
// Configure the DCMI interface.
|
||||||
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
// CSI config failed
|
omv_csi_t *csi = &csi_all[i];
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
|
||||||
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
csi->detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default color palette.
|
// Clear fb_enabled flag.
|
||||||
csi.color_palette = rainbow_table;
|
JPEG_FB()->enabled = 0;
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
|
|
||||||
// All good!
|
|
||||||
csi.detected = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAM_IRQHandler(void) {
|
void CAM_IRQHandler(void) {
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
CPI_Type *cpi = cpi_get_base_addr(&csi);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
CPI_Type *cpi = csi->base;
|
||||||
|
|
||||||
uint32_t status = cpi_get_interrupt_status(cpi);
|
uint32_t status = cpi_get_interrupt_status(cpi);
|
||||||
|
|
||||||
if (status & CAM_INTR_VSYNC) {
|
if (status & CAM_INTR_VSYNC) {
|
||||||
@ -470,19 +443,19 @@ void CAM_IRQHandler(void) {
|
|||||||
|
|
||||||
if (status & CAM_INTR_INFIFO_OVERRUN) {
|
if (status & CAM_INTR_INFIFO_OVERRUN) {
|
||||||
mask |= CAM_INTR_INFIFO_OVERRUN;
|
mask |= CAM_INTR_INFIFO_OVERRUN;
|
||||||
omv_csi_abort(&csi, true, true);
|
omv_csi_abort(csi, true, true);
|
||||||
printf("INFIFO_OVERRUN\n");
|
printf("INFIFO_OVERRUN\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & CAM_INTR_OUTFIFO_OVERRUN) {
|
if (status & CAM_INTR_OUTFIFO_OVERRUN) {
|
||||||
mask |= CAM_INTR_OUTFIFO_OVERRUN;
|
mask |= CAM_INTR_OUTFIFO_OVERRUN;
|
||||||
omv_csi_abort(&csi, true, true);
|
omv_csi_abort(csi, true, true);
|
||||||
printf("OUTFIFO_OVERRUN\n");
|
printf("OUTFIFO_OVERRUN\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & CAM_INTR_BRESP_ERR) {
|
if (status & CAM_INTR_BRESP_ERR) {
|
||||||
mask |= CAM_INTR_BRESP_ERR;
|
mask |= CAM_INTR_BRESP_ERR;
|
||||||
omv_csi_abort(&csi, true, true);
|
omv_csi_abort(csi, true, true);
|
||||||
printf("BRESP_ERR %lu\n", cpi->CAM_AXI_ERR_STAT);
|
printf("BRESP_ERR %lu\n", cpi->CAM_AXI_ERR_STAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,24 +464,22 @@ void CAM_IRQHandler(void) {
|
|||||||
cpi->CAM_CTRL = 0;
|
cpi->CAM_CTRL = 0;
|
||||||
if (!(status & CPI_ERROR_FLAGS)) {
|
if (!(status & CPI_ERROR_FLAGS)) {
|
||||||
// Release the current framebuffer.
|
// Release the current framebuffer.
|
||||||
framebuffer_get_tail(csi.fb, FB_NO_FLAGS);
|
framebuffer_get_tail(csi->fb, FB_NO_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current framebuffer (or new tail).
|
// Get the current framebuffer (or new tail).
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(csi.fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(csi->fb, FB_PEEK);
|
||||||
|
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
cpi->CAM_CTRL = 0;
|
cpi->CAM_CTRL = 0;
|
||||||
cpi->CAM_CTRL |= CAM_CTRL_SW_RESET;
|
cpi->CAM_CTRL |= CAM_CTRL_SW_RESET;
|
||||||
cpi->CAM_FRAME_ADDR = LocalToGlobal(buffer->data + omv_csi_get_fb_offset(&csi));
|
cpi->CAM_FRAME_ADDR = LocalToGlobal(buffer->data + omv_csi_get_fb_offset(csi));
|
||||||
cpi_irq_handler_clear_intr_status(cpi, mask);
|
cpi_irq_handler_clear_intr_status(cpi, mask);
|
||||||
cpi->CAM_CTRL = (CAM_CTRL_SNAPSHOT | CAM_CTRL_START | CAM_CTRL_FIFO_CLK_SEL);
|
cpi->CAM_CTRL = (CAM_CTRL_SNAPSHOT | CAM_CTRL_START | CAM_CTRL_FIFO_CLK_SEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(status & CPI_ERROR_FLAGS)) {
|
if (csi->frame_cb.fun && !(status & CPI_ERROR_FLAGS)) {
|
||||||
if (csi.frame_callback) {
|
csi->frame_cb.fun(csi->frame_cb.arg);
|
||||||
csi.frame_callback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "i3c.h"
|
#include "i3c.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
#include "cpi.h"
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "pinconf.h"
|
#include "pinconf.h"
|
||||||
|
|
||||||
@ -127,12 +128,18 @@ struct { \
|
|||||||
#define OMV_SPI_MAX_TIMEOUT (0xFFFFFFFF)
|
#define OMV_SPI_MAX_TIMEOUT (0xFFFFFFFF)
|
||||||
#define OMV_SPI_NO_DMA (1)
|
#define OMV_SPI_NO_DMA (1)
|
||||||
|
|
||||||
#define OMV_SPI_PORT_BITS \
|
#define OMV_SPI_PORT_BITS \
|
||||||
struct { \
|
struct { \
|
||||||
SPI_Type *inst; \
|
SPI_Type *inst; \
|
||||||
bool is_lp; \
|
bool is_lp; \
|
||||||
uint32_t spi_mode; \
|
uint32_t spi_mode; \
|
||||||
uint32_t bus_mode; \
|
uint32_t bus_mode; \
|
||||||
uint8_t datasize; \
|
uint8_t datasize; \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define OMV_CSI_PORT_BITS \
|
||||||
|
struct { \
|
||||||
|
CPI_Type *base; \
|
||||||
|
};
|
||||||
|
|
||||||
#endif // __OMV_PORTCONFIG_H__
|
#endif // __OMV_PORTCONFIG_H__
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
// Define pin objects in this file.
|
// Define pin objects in this file.
|
||||||
#define OMV_GPIO_DEFINE_PINS (1)
|
#define OMV_GPIO_DEFINE_PINS (1)
|
||||||
|
#include "omv_csi.h"
|
||||||
#include "omv_gpio.h"
|
#include "omv_gpio.h"
|
||||||
#include "mimxrt_hal.h"
|
#include "mimxrt_hal.h"
|
||||||
|
|
||||||
@ -320,9 +321,11 @@ int mimxrt_hal_spi_deinit(uint32_t bus_id, uint32_t bus_mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CSI_IRQHandler(void) {
|
void CSI_IRQHandler(void) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
uint32_t csisr = CSI_REG_SR(CSI);
|
uint32_t csisr = CSI_REG_SR(CSI);
|
||||||
extern void omv_csi_sof_callback();
|
|
||||||
extern void omv_csi_line_callback(uint32_t);
|
extern void omv_csi_sof_callback(omv_csi_t *csi);
|
||||||
|
extern void omv_csi_line_callback(omv_csi_t *csi, uint32_t);
|
||||||
|
|
||||||
// Clear interrupt flags.
|
// Clear interrupt flags.
|
||||||
CSI_REG_SR(CSI) = csisr;
|
CSI_REG_SR(CSI) = csisr;
|
||||||
@ -330,11 +333,11 @@ void CSI_IRQHandler(void) {
|
|||||||
if (csisr & CSI_SR_SOF_INT_MASK) {
|
if (csisr & CSI_SR_SOF_INT_MASK) {
|
||||||
// Clear the FIFO and re/enable DMA.
|
// Clear the FIFO and re/enable DMA.
|
||||||
CSI_REG_CR3(CSI) |= (CSI_CR3_DMA_REFLASH_RFF_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
|
CSI_REG_CR3(CSI) |= (CSI_CR3_DMA_REFLASH_RFF_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
|
||||||
omv_csi_sof_callback();
|
omv_csi_sof_callback(csi);
|
||||||
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB1_MASK) {
|
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB1_MASK) {
|
||||||
omv_csi_line_callback(CSI_REG_DMASA_FB1(CSI));
|
omv_csi_line_callback(csi, CSI_REG_DMASA_FB1(CSI));
|
||||||
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB2_MASK) {
|
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB2_MASK) {
|
||||||
omv_csi_line_callback(CSI_REG_DMASA_FB2(CSI));
|
omv_csi_line_callback(csi, CSI_REG_DMASA_FB2(CSI));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate
|
// Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate
|
||||||
|
@ -54,26 +54,7 @@ extern uint8_t _line_buf[OMV_LINE_BUF_SIZE];
|
|||||||
| CSI_CR1_FB2_DMA_DONE_INTEN_MASK \
|
| CSI_CR1_FB2_DMA_DONE_INTEN_MASK \
|
||||||
| CSI_CR1_FB1_DMA_DONE_INTEN_MASK)
|
| CSI_CR1_FB1_DMA_DONE_INTEN_MASK)
|
||||||
|
|
||||||
void omv_csi_init0() {
|
int imx_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
omv_csi_abort(&csi, true, false);
|
|
||||||
|
|
||||||
// Re-init I2C to reset the bus state after soft reset, which
|
|
||||||
// could have interrupted the bus in the middle of a transfer.
|
|
||||||
if (csi.i2c->initialized) {
|
|
||||||
// Reinitialize the bus using the last used id and speed.
|
|
||||||
omv_i2c_init(csi.i2c, csi.i2c->id, csi.i2c->speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
csi.disable_delays = false;
|
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
|
||||||
if (config == OMV_CSI_CONFIG_INIT) {
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
CSI_Reset(CSI);
|
CSI_Reset(CSI);
|
||||||
NVIC_DisableIRQ(CSI_IRQn);
|
NVIC_DisableIRQ(CSI_IRQn);
|
||||||
@ -88,9 +69,9 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
|
|
||||||
// Configure VSYNC, HSYNC and PIXCLK signals.
|
// Configure VSYNC, HSYNC and PIXCLK signals.
|
||||||
CSI_REG_CR1(CSI) |= CSI_CR1_EXT_VSYNC_MASK;
|
CSI_REG_CR1(CSI) |= CSI_CR1_EXT_VSYNC_MASK;
|
||||||
CSI_REG_CR1(CSI) |= !csi.vsync_pol ? CSI_CR1_SOF_POL_MASK : 0;
|
CSI_REG_CR1(CSI) |= !csi->vsync_pol ? CSI_CR1_SOF_POL_MASK : 0;
|
||||||
CSI_REG_CR1(CSI) |= !csi.hsync_pol ? CSI_CR1_HSYNC_POL_MASK : 0;
|
CSI_REG_CR1(CSI) |= !csi->hsync_pol ? CSI_CR1_HSYNC_POL_MASK : 0;
|
||||||
CSI_REG_CR1(CSI) |= csi.pixck_pol ? CSI_CR1_REDGE_MASK : 0;
|
CSI_REG_CR1(CSI) |= csi->pixck_pol ? CSI_CR1_REDGE_MASK : 0;
|
||||||
|
|
||||||
// Stride config: No stride.
|
// Stride config: No stride.
|
||||||
CSI_REG_FBUF_PARA(CSI) = 0;
|
CSI_REG_FBUF_PARA(CSI) = 0;
|
||||||
@ -112,28 +93,19 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
static int imx_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
NVIC_DisableIRQ(CSI_IRQn);
|
NVIC_DisableIRQ(CSI_IRQn);
|
||||||
CSI_DisableInterrupts(CSI, CSI_IRQ_FLAGS);
|
CSI_DisableInterrupts(CSI, CSI_IRQ_FLAGS);
|
||||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||||
CSI_REG_CR18(CSI) &= ~CSI_CR18_CSI_ENABLE_MASK;
|
CSI_REG_CR18(CSI) &= ~CSI_CR18_CSI_ENABLE_MASK;
|
||||||
|
|
||||||
csi->dest_inc = 0;
|
csi->dest_inc = 0;
|
||||||
csi->first_line = false;
|
|
||||||
csi->drop_frame = false;
|
|
||||||
csi->last_frame_ms = 0;
|
|
||||||
csi->last_frame_ms_valid = false;
|
|
||||||
|
|
||||||
if (csi->fb) {
|
|
||||||
if (fifo_flush) {
|
|
||||||
framebuffer_flush_buffers(csi->fb, true);
|
|
||||||
} else if (!csi->disable_full_flush) {
|
|
||||||
framebuffer_flush_buffers(csi->fb, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t omv_csi_get_clk_frequency() {
|
||||||
|
return 24000000 / (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
int omv_csi_set_clk_frequency(uint32_t frequency) {
|
||||||
if (frequency >= 24000000) {
|
if (frequency >= 24000000) {
|
||||||
CLOCK_SetDiv(kCLOCK_CsiDiv, 0);
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 0);
|
||||||
@ -151,46 +123,42 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
void omv_csi_sof_callback(omv_csi_t *csi) {
|
||||||
return 24000000 / (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1);
|
csi->first_line = false;
|
||||||
}
|
csi->drop_frame = false;
|
||||||
|
|
||||||
void omv_csi_sof_callback() {
|
|
||||||
csi.first_line = false;
|
|
||||||
csi.drop_frame = false;
|
|
||||||
|
|
||||||
// Get current framebuffer.
|
// Get current framebuffer.
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(csi.fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(csi->fb, FB_PEEK);
|
||||||
|
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
omv_csi_abort(&csi, false, true);
|
omv_csi_abort(csi, false, true);
|
||||||
} else if (buffer->offset < resolution[csi.framesize][1]) {
|
} else if (buffer->offset < resolution[csi->framesize][1]) {
|
||||||
// Missed a few lines, reset buffer state and continue.
|
// Missed a few lines, reset buffer state and continue.
|
||||||
buffer->reset_state = true;
|
buffer->reset_state = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OMV_CSI_DMA)
|
#if defined(OMV_CSI_DMA)
|
||||||
int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
|
int omv_csi_dma_memcpy(omv_csi_t *csi, void *dma, void *dst, void *src, int bpp, bool transposed) {
|
||||||
|
edma_handle_t *handle = dma;
|
||||||
|
edma_transfer_config_t config;
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// EMDA will not perform burst transfers for anything less than 32-byte chunks of four 64-bit
|
// EMDA will not perform burst transfers for anything less than 32-byte chunks of four 64-bit
|
||||||
// beats. Additionally, the CSI hardware lacks cropping so we cannot align the source address.
|
// beats. Additionally, the CSI hardware lacks cropping so we cannot align the source address.
|
||||||
// Given this, performance will be lacking on cropped images. So much so that we do not use
|
// Given this, performance will be lacking on cropped images. So much so that we do not use
|
||||||
// the EDMA for anything less than 4-byte transfers otherwise you get sensor timeout errors.
|
// the EDMA for anything less than 4-byte transfers otherwise you get sensor timeout errors.
|
||||||
if (csi.dest_inc < MIN_EDMA_DST_INC) {
|
if (csi->dest_inc < MIN_EDMA_DST_INC) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
edma_handle_t *handle = dma;
|
|
||||||
edma_transfer_config_t config;
|
|
||||||
framebuffer_t *fb = csi.fb;
|
|
||||||
|
|
||||||
EDMA_PrepareTransferConfig(&config,
|
EDMA_PrepareTransferConfig(&config,
|
||||||
src, // srcAddr
|
src, // srcAddr
|
||||||
csi.src_size, // srcWidth
|
csi->src_size, // srcWidth
|
||||||
csi.src_inc, // srcOffset
|
csi->src_inc, // srcOffset
|
||||||
dst, // destAddr
|
dst, // destAddr
|
||||||
transposed ? bpp : csi.dest_inc, // destWidth
|
transposed ? bpp : csi->dest_inc, // destWidth
|
||||||
transposed ? (fb->v * bpp) : csi.dest_inc, // destOffset
|
transposed ? (fb->v * bpp) : csi->dest_inc, // destOffset
|
||||||
fb->u * bpp, // bytesEachRequest
|
fb->u * bpp, // bytesEachRequest
|
||||||
fb->u * bpp); // transferBytes
|
fb->u * bpp); // transferBytes
|
||||||
|
|
||||||
@ -203,7 +171,7 @@ int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed
|
|||||||
}
|
}
|
||||||
if (--retry == 0) {
|
if (--retry == 0) {
|
||||||
// Drop the frame if EDMA is not keeping up as the image will be corrupt.
|
// Drop the frame if EDMA is not keeping up as the image will be corrupt.
|
||||||
csi.drop_frame = true;
|
csi->drop_frame = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,21 +181,21 @@ int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void omv_csi_line_callback(uint32_t addr) {
|
void omv_csi_line_callback(omv_csi_t *csi, uint32_t addr) {
|
||||||
framebuffer_t *fb = csi.fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Throttle frames to match the current frame rate.
|
// Throttle frames to match the current frame rate.
|
||||||
omv_csi_throttle_framerate();
|
omv_csi_throttle_framerate(csi);
|
||||||
|
|
||||||
// Get current framebuffer.
|
// Get current framebuffer.
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_JPEG) {
|
if (csi->pixformat == PIXFORMAT_JPEG) {
|
||||||
if (csi.drop_frame) {
|
if (csi->drop_frame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool jpeg_end = false;
|
bool jpeg_end = false;
|
||||||
if (csi.jpg_format == 4) {
|
if (csi->jpg_format == 4) {
|
||||||
// JPEG MODE 4:
|
// JPEG MODE 4:
|
||||||
//
|
//
|
||||||
// The width and height are fixed in each frame. The first two bytes are valid data
|
// The width and height are fixed in each frame. The first two bytes are valid data
|
||||||
@ -257,7 +225,7 @@ void omv_csi_line_callback(uint32_t addr) {
|
|||||||
}
|
}
|
||||||
buffer->offset += size;
|
buffer->offset += size;
|
||||||
}
|
}
|
||||||
} else if (csi.jpg_format == 3) {
|
} else if (csi->jpg_format == 3) {
|
||||||
// OV2640 JPEG TODO
|
// OV2640 JPEG TODO
|
||||||
}
|
}
|
||||||
// In JPEG mode the camera sensor will output some number of lines that doesn't match the
|
// In JPEG mode the camera sensor will output some number of lines that doesn't match the
|
||||||
@ -267,16 +235,16 @@ void omv_csi_line_callback(uint32_t addr) {
|
|||||||
// Release the current framebuffer.
|
// Release the current framebuffer.
|
||||||
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||||
if (csi.frame_callback) {
|
if (csi->frame_cb.fun) {
|
||||||
csi.frame_callback();
|
csi->frame_cb.fun(csi->frame_cb.arg);
|
||||||
}
|
}
|
||||||
csi.drop_frame = true;
|
csi->drop_frame = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csi.drop_frame) {
|
if (csi->drop_frame) {
|
||||||
if (++buffer->offset == resolution[csi.framesize][1]) {
|
if (++buffer->offset == resolution[csi->framesize][1]) {
|
||||||
buffer->offset = 0;
|
buffer->offset = 0;
|
||||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||||
}
|
}
|
||||||
@ -285,16 +253,16 @@ void omv_csi_line_callback(uint32_t addr) {
|
|||||||
|
|
||||||
if ((fb->y <= buffer->offset) && (buffer->offset < (fb->y + fb->v))) {
|
if ((fb->y <= buffer->offset) && (buffer->offset < (fb->y + fb->v))) {
|
||||||
// Copy from DMA buffer to framebuffer.
|
// Copy from DMA buffer to framebuffer.
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint8_t *src = ((uint8_t *) addr) + (fb->x * bytes_per_pixel);
|
uint8_t *src = ((uint8_t *) addr) + (fb->x * bytes_per_pixel);
|
||||||
uint8_t *dst = buffer->data;
|
uint8_t *dst = buffer->data;
|
||||||
|
|
||||||
// Adjust BPP for Grayscale.
|
// Adjust BPP for Grayscale.
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
bytes_per_pixel = 1;
|
bytes_per_pixel = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csi.transpose) {
|
if (csi->transpose) {
|
||||||
dst += bytes_per_pixel * (buffer->offset - fb->y);
|
dst += bytes_per_pixel * (buffer->offset - fb->y);
|
||||||
} else {
|
} else {
|
||||||
dst += fb->u * bytes_per_pixel * (buffer->offset - fb->y);
|
dst += fb->u * bytes_per_pixel * (buffer->offset - fb->y);
|
||||||
@ -304,18 +272,18 @@ void omv_csi_line_callback(uint32_t addr) {
|
|||||||
// We're using multiple handles to give each channel the maximum amount of time possible to do the line
|
// We're using multiple handles to give each channel the maximum amount of time possible to do the line
|
||||||
// transfer. In most situations only one channel will be running at a time. However, if SDRAM is
|
// transfer. In most situations only one channel will be running at a time. However, if SDRAM is
|
||||||
// backedup we don't have to disable the channel if it is flushing trailing data to SDRAM.
|
// backedup we don't have to disable the channel if it is flushing trailing data to SDRAM.
|
||||||
omv_csi_copy_line(&csi.dma_channels[buffer->offset % OMV_CSI_DMA_CHANNEL_COUNT], src, dst);
|
omv_csi_copy_line(csi, &csi->dma_channels[buffer->offset % OMV_CSI_DMA_CHANNEL_COUNT], src, dst);
|
||||||
#else
|
#else
|
||||||
omv_csi_copy_line(NULL, src, dst);
|
omv_csi_copy_line(csi, NULL, src, dst);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++buffer->offset == resolution[csi.framesize][1]) {
|
if (++buffer->offset == resolution[csi->framesize][1]) {
|
||||||
// Release the current framebuffer.
|
// Release the current framebuffer.
|
||||||
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||||
if (csi.frame_callback) {
|
if (csi->frame_cb.fun) {
|
||||||
csi.frame_callback();
|
csi->frame_cb.fun(csi->frame_cb.arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,7 +329,7 @@ static void edma_config(omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
int imx_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Used to restore the frame buffer width and height.
|
// Used to restore the frame buffer width and height.
|
||||||
@ -376,7 +344,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (omv_csi_check_framebuffer_size() != 0) {
|
if (omv_csi_check_framebuffer_size(csi) != 0) {
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +358,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
if (!(CSI->CR18 & CSI_CR18_CSI_ENABLE_MASK)) {
|
if (!(CSI->CR18 & CSI_CR18_CSI_ENABLE_MASK)) {
|
||||||
framebuffer_setup_buffers(fb);
|
framebuffer_setup_buffers(fb);
|
||||||
|
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint32_t dma_line_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
uint32_t dma_line_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
||||||
uint32_t length = dma_line_bytes * h;
|
uint32_t length = dma_line_bytes * h;
|
||||||
|
|
||||||
@ -530,10 +498,10 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
framebuffer_init_image(fb, image);
|
framebuffer_init_image(fb, image);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int init_ret = 0;
|
||||||
|
static omv_i2c_t i2c;
|
||||||
|
|
||||||
mimxrt_hal_csi_init(CSI);
|
mimxrt_hal_csi_init(CSI);
|
||||||
|
|
||||||
@ -545,18 +513,19 @@ int omv_csi_init() {
|
|||||||
omv_gpio_write(OMV_CSI_RESET_PIN, 1);
|
omv_gpio_write(OMV_CSI_RESET_PIN, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->abort = imx_csi_abort;
|
||||||
csi.i2c = &csi_i2c;
|
csi->config = imx_csi_config;
|
||||||
|
csi->snapshot = imx_csi_snapshot;
|
||||||
// Set default snapshot function.
|
csi->color_palette = rainbow_table;
|
||||||
// Some sensors need to call snapshot from init.
|
}
|
||||||
csi.snapshot = omv_csi_snapshot;
|
|
||||||
|
|
||||||
// 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(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
@ -564,29 +533,28 @@ int omv_csi_init() {
|
|||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the camera bus.
|
||||||
|
omv_i2c_init(&i2c, OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED);
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// Detect and initialize the image sensor.
|
||||||
if ((init_ret = omv_csi_probe_init(OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED)) != 0) {
|
if ((init_ret = omv_csi_probe(&i2c)) != 0) {
|
||||||
// Sensor probe/init failed.
|
// Sensor probe/init failed.
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the CSI interface.
|
// Configure the CSI interfaces.
|
||||||
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
// CSI config failed
|
omv_csi_t *csi = &csi_all[i];
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
|
||||||
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
csi->detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default color palette.
|
// Clear fb_enabled flag.
|
||||||
csi.color_palette = rainbow_table;
|
JPEG_FB()->enabled = 0;
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
|
|
||||||
// All good!
|
|
||||||
csi.detected = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif // MICROPY_PY_CSI
|
||||||
|
@ -61,7 +61,7 @@ static const volatile uint32_t *_pclkPort;
|
|||||||
|
|
||||||
extern void __fatal_error(const char *msg);
|
extern void __fatal_error(const char *msg);
|
||||||
|
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
static int nrf_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_INIT) {
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
uint32_t csi_pins[] = {
|
uint32_t csi_pins[] = {
|
||||||
OMV_CSI_D0_PIN,
|
OMV_CSI_D0_PIN,
|
||||||
@ -114,12 +114,12 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_windowing(int x, int y, int w, int h) {
|
int omv_csi_set_windowing(omv_csi_t *csi, int x, int y, int w, int h) {
|
||||||
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
static int nrf_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Compress the framebuffer for the IDE preview, only if it's not the first frame,
|
// Compress the framebuffer for the IDE preview, only if it's not the first frame,
|
||||||
@ -132,7 +132,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
framebuffer_set_buffers(fb, 1);
|
framebuffer_set_buffers(fb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (omv_csi_check_framebuffer_size(fb) != 0) {
|
if (omv_csi_check_framebuffer_size(csi) != 0) {
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +188,8 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
interrupts();
|
interrupts();
|
||||||
|
|
||||||
// Not useful for the NRF but must call to keep API the same.
|
// Not useful for the NRF but must call to keep API the same.
|
||||||
if (csi->frame_callback) {
|
if (csi->frame_cb.fun) {
|
||||||
csi->frame_callback();
|
csi->frame_cb.fun(csi->frame_cb.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set framebuffer pixel format.
|
// Set framebuffer pixel format.
|
||||||
@ -208,6 +208,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int init_ret = 0;
|
||||||
|
static omv_i2c_t i2c;
|
||||||
|
|
||||||
#if defined(OMV_CSI_POWER_PIN)
|
#if defined(OMV_CSI_POWER_PIN)
|
||||||
nrf_gpio_cfg_output(OMV_CSI_POWER_PIN);
|
nrf_gpio_cfg_output(OMV_CSI_POWER_PIN);
|
||||||
@ -219,17 +220,19 @@ int omv_csi_init() {
|
|||||||
nrf_gpio_pin_write(OMV_CSI_RESET_PIN, 1);
|
nrf_gpio_pin_write(OMV_CSI_RESET_PIN, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->abort = NULL;
|
||||||
csi.i2c = &csi_i2c;
|
csi->config = nrf_csi_config;
|
||||||
|
csi->snapshot = nrf_csi_snapshot;
|
||||||
// Set default snapshot function.
|
csi->color_palette = rainbow_table;
|
||||||
csi.snapshot = omv_csi_snapshot;
|
}
|
||||||
|
|
||||||
// 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(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
@ -237,30 +240,28 @@ int omv_csi_init() {
|
|||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the camera bus.
|
||||||
|
omv_i2c_init(&i2c, OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED);
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// Detect and initialize the image sensor.
|
||||||
if ((init_ret = omv_csi_probe_init(OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED)) != 0) {
|
if ((init_ret = omv_csi_probe(&i2c)) != 0) {
|
||||||
// Sensor probe/init failed.
|
// Sensor probe/init failed.
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the CSI interface.
|
// Configure the CSI interfaces.
|
||||||
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
// CSI config failed
|
omv_csi_t *csi = &csi_all[i];
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
|
||||||
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
csi->detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear fb_enabled flag
|
// Clear fb_enabled flag
|
||||||
// This is executed only once to initialize the FB enabled flag.
|
JPEG_FB()->enabled = 0;
|
||||||
//JPEG_FB()->enabled = 0;
|
|
||||||
|
|
||||||
// Set default color palette.
|
|
||||||
csi.color_palette = rainbow_table;
|
|
||||||
|
|
||||||
csi.detected = true;
|
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
/* All good! */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -41,31 +41,56 @@
|
|||||||
#include "unaligned_memcpy.h"
|
#include "unaligned_memcpy.h"
|
||||||
#include "dcmi.pio.h"
|
#include "dcmi.pio.h"
|
||||||
|
|
||||||
static void dma_irq_handler();
|
|
||||||
extern void __fatal_error(const char *msg);
|
extern void __fatal_error(const char *msg);
|
||||||
|
|
||||||
static void omv_csi_dma_config(int w, int h, int bpp, uint32_t *capture_buf, bool rev_bytes) {
|
static void dma_irq_handler() {
|
||||||
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
dma_channel_config c = dma_channel_get_default_config(OMV_CSI_DMA_CHANNEL);
|
if (dma_irqn_get_channel_status(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL)) {
|
||||||
channel_config_set_read_increment(&c, false);
|
// Clear the interrupt request.
|
||||||
channel_config_set_write_increment(&c, true);
|
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
||||||
channel_config_set_dreq(&c, pio_get_dreq(OMV_CSI_PIO, OMV_CSI_SM, false));
|
|
||||||
channel_config_set_bswap(&c, rev_bytes);
|
|
||||||
|
|
||||||
dma_channel_configure(OMV_CSI_DMA_CHANNEL, &c,
|
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||||
capture_buf, // Destinatinon pointer.
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
&OMV_CSI_PIO->rxf[OMV_CSI_SM], // Source pointer.
|
if (buffer != NULL) {
|
||||||
(w * h * bpp) >> 2, // Number of transfers in words.
|
// Set next buffer and retrigger the DMA channel.
|
||||||
true // Start immediately, will block on SM.
|
dma_channel_set_write_addr(OMV_CSI_DMA_CHANNEL, buffer->data, true);
|
||||||
);
|
|
||||||
|
|
||||||
// Re-enable DMA IRQs.
|
// Unblock the state machine
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, true);
|
pio_sm_restart(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
|
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
|
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->v - 1));
|
||||||
|
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->u * fb->bpp) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
static int rp2_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
|
// Install new DMA IRQ handler.
|
||||||
|
irq_set_enabled(OMV_CSI_DMA_IRQ, false);
|
||||||
|
|
||||||
|
// Clear DMA interrupts.
|
||||||
|
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
||||||
|
|
||||||
|
// Remove current handler if any
|
||||||
|
irq_handler_t irq_handler = irq_get_exclusive_handler(OMV_CSI_DMA_IRQ);
|
||||||
|
if (irq_handler != NULL) {
|
||||||
|
irq_remove_handler(OMV_CSI_DMA_IRQ, irq_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new exclusive IRQ handler.
|
||||||
|
irq_set_exclusive_handler(OMV_CSI_DMA_IRQ, dma_irq_handler);
|
||||||
|
// Or set shared IRQ handler, but this needs to be called once.
|
||||||
|
// irq_add_shared_handler(OMV_CSI_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY);
|
||||||
|
|
||||||
|
irq_set_enabled(OMV_CSI_DMA_IRQ, true);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rp2_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
// Disable DMA channel
|
// Disable DMA channel
|
||||||
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
||||||
@ -107,39 +132,17 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_windowing(int x, int y, int w, int h) {
|
int omv_csi_set_windowing(omv_csi_t *csi, int x, int y, int w, int h) {
|
||||||
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_irq_handler() {
|
static int rp2_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
framebuffer_t *fb = csi.fb;
|
|
||||||
|
|
||||||
if (dma_irqn_get_channel_status(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL)) {
|
|
||||||
// Clear the interrupt request.
|
|
||||||
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
|
||||||
|
|
||||||
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
|
||||||
if (buffer != NULL) {
|
|
||||||
// Set next buffer and retrigger the DMA channel.
|
|
||||||
dma_channel_set_write_addr(OMV_CSI_DMA_CHANNEL, buffer->data, true);
|
|
||||||
|
|
||||||
// Unblock the state machine
|
|
||||||
pio_sm_restart(OMV_CSI_PIO, OMV_CSI_SM);
|
|
||||||
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
|
||||||
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->v - 1));
|
|
||||||
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->u * fb->bpp) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Compress the framebuffer for the IDE preview.
|
// Compress the framebuffer for the IDE preview.
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
|
|
||||||
if (omv_csi_check_framebuffer_size() != 0) {
|
if (omv_csi_check_framebuffer_size(csi) != 0) {
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,10 +167,25 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the DMA on the first frame, for later frames only the write is changed.
|
// Configure the DMA on the first frame.
|
||||||
omv_csi_dma_config(fb->u, fb->v, fb->bpp,
|
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
||||||
(void *) buffer->data,
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
||||||
(csi->rgb_swap && fb->bpp == 2));
|
|
||||||
|
dma_channel_config c = dma_channel_get_default_config(OMV_CSI_DMA_CHANNEL);
|
||||||
|
channel_config_set_read_increment(&c, false);
|
||||||
|
channel_config_set_write_increment(&c, true);
|
||||||
|
channel_config_set_dreq(&c, pio_get_dreq(OMV_CSI_PIO, OMV_CSI_SM, false));
|
||||||
|
channel_config_set_bswap(&c, csi->rgb_swap && (fb->bpp == 2));
|
||||||
|
|
||||||
|
dma_channel_configure(OMV_CSI_DMA_CHANNEL, &c,
|
||||||
|
(uint32_t *) buffer->data, // Destinatinon pointer.
|
||||||
|
&OMV_CSI_PIO->rxf[OMV_CSI_SM], // Source pointer.
|
||||||
|
(fb->u * fb->v * fb->bpp) >> 2, // Number of transfers in words.
|
||||||
|
true // Start immediately, will block on SM.
|
||||||
|
);
|
||||||
|
|
||||||
|
// Re-enable DMA IRQs.
|
||||||
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, true);
|
||||||
|
|
||||||
// Re-enable the state machine.
|
// Re-enable the state machine.
|
||||||
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
@ -194,10 +212,10 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
framebuffer_init_image(fb, image);
|
framebuffer_init_image(fb, image);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int init_ret = 0;
|
||||||
|
static omv_i2c_t i2c;
|
||||||
|
|
||||||
// PIXCLK
|
// PIXCLK
|
||||||
gpio_init(OMV_CSI_PXCLK_PIN);
|
gpio_init(OMV_CSI_PXCLK_PIN);
|
||||||
@ -225,17 +243,19 @@ int omv_csi_init() {
|
|||||||
gpio_put(OMV_CSI_RESET_PIN, 1);
|
gpio_put(OMV_CSI_RESET_PIN, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->abort = rp2_csi_abort;
|
||||||
csi.i2c = &csi_i2c;
|
csi->config = rp2_csi_config;
|
||||||
|
csi->snapshot = rp2_csi_snapshot;
|
||||||
// Set default snapshot function.
|
csi->color_palette = rainbow_table;
|
||||||
csi.snapshot = omv_csi_snapshot;
|
}
|
||||||
|
|
||||||
// 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(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
@ -243,43 +263,28 @@ int omv_csi_init() {
|
|||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the camera bus.
|
||||||
|
omv_i2c_init(&i2c, OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED);
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// Detect and initialize the image sensor.
|
||||||
if ((init_ret = omv_csi_probe_init(OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED)) != 0) {
|
if ((init_ret = omv_csi_probe(&i2c)) != 0) {
|
||||||
// Sensor probe/init failed.
|
// Sensor probe/init failed.
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default color palette.
|
// Configure the DCMI interface.
|
||||||
csi.color_palette = rainbow_table;
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set new DMA IRQ handler.
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
// Disable IRQs.
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
irq_set_enabled(OMV_CSI_DMA_IRQ, false);
|
}
|
||||||
|
|
||||||
// Clear DMA interrupts.
|
csi->detected = true;
|
||||||
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
|
||||||
|
|
||||||
// Remove current handler if any
|
|
||||||
irq_handler_t irq_handler = irq_get_exclusive_handler(OMV_CSI_DMA_IRQ);
|
|
||||||
if (irq_handler != NULL) {
|
|
||||||
irq_remove_handler(OMV_CSI_DMA_IRQ, irq_handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new exclusive IRQ handler.
|
// Clear fb_enabled flag.
|
||||||
irq_set_exclusive_handler(OMV_CSI_DMA_IRQ, dma_irq_handler);
|
JPEG_FB()->enabled = 0;
|
||||||
// Or set shared IRQ handler, but this needs to be called once.
|
|
||||||
// irq_add_shared_handler(OMV_CSI_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY);
|
|
||||||
|
|
||||||
irq_set_enabled(OMV_CSI_DMA_IRQ, true);
|
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
|
|
||||||
/* All good! */
|
|
||||||
csi.detected = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif // MICROPY_PY_CSI
|
||||||
|
@ -70,94 +70,82 @@ extern uint32_t hal_get_exti_gpio(uint32_t line);
|
|||||||
|
|
||||||
#if USE_DCMI
|
#if USE_DCMI
|
||||||
void DCMI_IRQHandler(void) {
|
void DCMI_IRQHandler(void) {
|
||||||
HAL_DCMI_IRQHandler(&csi.dcmi);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
HAL_DCMI_IRQHandler(&csi->dcmi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_DCMIPP
|
#if USE_DCMIPP
|
||||||
void CSI_IRQHandler(void) {
|
void CSI_IRQHandler(void) {
|
||||||
HAL_DCMIPP_CSI_IRQHandler(&csi.dcmi);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
HAL_DCMIPP_CSI_IRQHandler(&csi->dcmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCMIPP_IRQHandler(void) {
|
void DCMIPP_IRQHandler(void) {
|
||||||
HAL_DCMIPP_IRQHandler(&csi.dcmi);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
HAL_DCMIPP_IRQHandler(&csi->dcmi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
void omv_csi_mdma_irq_handler(void) {
|
void omv_csi_mdma_irq_handler(void) {
|
||||||
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_0)) {
|
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_0)) {
|
||||||
HAL_MDMA_IRQHandler(&csi.mdma0);
|
HAL_MDMA_IRQHandler(&csi->mdma0);
|
||||||
}
|
}
|
||||||
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_1)) {
|
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_1)) {
|
||||||
HAL_MDMA_IRQHandler(&csi.mdma1);
|
HAL_MDMA_IRQHandler(&csi->mdma1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void omv_csi_init0() {
|
static int stm_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
omv_csi_abort(&csi, true, false);
|
|
||||||
|
|
||||||
// Disable callbacks
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
|
|
||||||
csi.disable_delays = false;
|
|
||||||
|
|
||||||
// Re-init i2c bus to reset the bus state after soft reset, which
|
|
||||||
// could have interrupted the bus in the middle of a transfer.
|
|
||||||
if (csi.i2c->initialized) {
|
|
||||||
// Reinitialize the bus using the last used id and speed.
|
|
||||||
omv_i2c_init(csi.i2c, csi.i2c->id, csi.i2c->speed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
|
||||||
if (config == OMV_CSI_CONFIG_INIT) {
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
#if USE_DMA
|
#if USE_DMA
|
||||||
// DMA Stream configuration
|
// DMA Stream configuration
|
||||||
csi.dma.Instance = DMA2_Stream1;
|
csi->dma.Instance = DMA2_Stream1;
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7)
|
||||||
csi.dma.Init.Request = DMA_REQUEST_DCMI;
|
csi->dma.Init.Request = DMA_REQUEST_DCMI;
|
||||||
#else
|
#else
|
||||||
csi.dma.Init.Channel = DMA_CHANNEL_1;
|
csi->dma.Init.Channel = DMA_CHANNEL_1;
|
||||||
#endif
|
#endif
|
||||||
csi.dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
csi->dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||||
csi.dma.Init.MemInc = DMA_MINC_ENABLE;
|
csi->dma.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
csi.dma.Init.PeriphInc = DMA_PINC_DISABLE;
|
csi->dma.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
csi.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
csi->dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||||
csi.dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
csi->dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||||
csi.dma.Init.Mode = DMA_NORMAL;
|
csi->dma.Init.Mode = DMA_NORMAL;
|
||||||
csi.dma.Init.Priority = DMA_PRIORITY_HIGH;
|
csi->dma.Init.Priority = DMA_PRIORITY_HIGH;
|
||||||
csi.dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
|
csi->dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
|
||||||
csi.dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
csi->dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||||
csi.dma.Init.MemBurst = DMA_MBURST_INC4;
|
csi->dma.Init.MemBurst = DMA_MBURST_INC4;
|
||||||
csi.dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
csi->dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
||||||
|
|
||||||
// Initialize the DMA stream
|
// Initialize the DMA stream
|
||||||
HAL_DMA_DeInit(&csi.dma);
|
HAL_DMA_DeInit(&csi->dma);
|
||||||
if (HAL_DMA_Init(&csi.dma) != HAL_OK) {
|
if (HAL_DMA_Init(&csi->dma) != HAL_OK) {
|
||||||
return -1;
|
return OMV_CSI_ERROR_DMA_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set DMA IRQ handle
|
// Set DMA IRQ handle
|
||||||
dma_utils_set_irq_descr(DMA2_Stream1, &csi.dma);
|
dma_utils_set_irq_descr(DMA2_Stream1, &csi->dma);
|
||||||
|
|
||||||
// Configure the DMA IRQ Channel
|
// Configure the DMA IRQ Channel
|
||||||
NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21);
|
NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21);
|
||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
csi.mdma0.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_0);
|
csi->mdma0.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_0);
|
||||||
csi.mdma1.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_1);
|
csi->mdma1.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // USE_DMA
|
#endif // USE_DMA
|
||||||
|
|
||||||
// Configure DCMI/PP.
|
// Configure DCMI/PP.
|
||||||
#if USE_DCMIPP
|
#if USE_DCMIPP
|
||||||
// Initialize the DCMIPP
|
// Initialize the DCMIPP
|
||||||
csi.dcmi.Instance = DCMIPP;
|
csi->dcmi.Instance = DCMIPP;
|
||||||
if (HAL_DCMIPP_Init(&csi.dcmi) != HAL_OK) {
|
if (HAL_DCMIPP_Init(&csi->dcmi) != HAL_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,21 +157,21 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
NVIC_SetPriority(CSI_IRQn, IRQ_PRI_DCMI);
|
NVIC_SetPriority(CSI_IRQn, IRQ_PRI_DCMI);
|
||||||
HAL_NVIC_EnableIRQ(CSI_IRQn);
|
HAL_NVIC_EnableIRQ(CSI_IRQn);
|
||||||
#else
|
#else
|
||||||
csi.dcmi.Instance = DCMI;
|
csi->dcmi.Instance = DCMI;
|
||||||
csi.dcmi.Init.VSPolarity = csi.vsync_pol ? DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW;
|
csi->dcmi.Init.VSPolarity = csi->vsync_pol ? DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW;
|
||||||
csi.dcmi.Init.HSPolarity = csi.hsync_pol ? DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW;
|
csi->dcmi.Init.HSPolarity = csi->hsync_pol ? DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW;
|
||||||
csi.dcmi.Init.PCKPolarity = csi.pixck_pol ? DCMI_PCKPOLARITY_RISING : DCMI_PCKPOLARITY_FALLING;
|
csi->dcmi.Init.PCKPolarity = csi->pixck_pol ? DCMI_PCKPOLARITY_RISING : DCMI_PCKPOLARITY_FALLING;
|
||||||
csi.dcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
|
csi->dcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
|
||||||
csi.dcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
|
csi->dcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
|
||||||
csi.dcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
|
csi->dcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
|
||||||
csi.dcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
|
csi->dcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
|
||||||
|
|
||||||
// Link the DMA handle to the DCMI handle
|
// Link the DMA handle to the DCMI handle
|
||||||
__HAL_LINKDMA(&csi.dcmi, DMA_Handle, csi.dma);
|
__HAL_LINKDMA(&csi->dcmi, DMA_Handle, csi->dma);
|
||||||
|
|
||||||
// Initialize the DCMI
|
// Initialize the DCMI
|
||||||
HAL_DCMI_DeInit(&csi.dcmi);
|
HAL_DCMI_DeInit(&csi->dcmi);
|
||||||
if (HAL_DCMI_Init(&csi.dcmi) != HAL_OK) {
|
if (HAL_DCMI_Init(&csi->dcmi) != HAL_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,16 +182,16 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
} else if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
} else if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
#if USE_DCMI
|
#if USE_DCMI
|
||||||
DCMI->CR &= ~(DCMI_CR_JPEG_Msk << DCMI_CR_JPEG_Pos);
|
DCMI->CR &= ~(DCMI_CR_JPEG_Msk << DCMI_CR_JPEG_Pos);
|
||||||
DCMI->CR |= (csi.pixformat == PIXFORMAT_JPEG) ? DCMI_JPEG_ENABLE : DCMI_JPEG_DISABLE;
|
DCMI->CR |= (csi->pixformat == PIXFORMAT_JPEG) ? DCMI_JPEG_ENABLE : DCMI_JPEG_DISABLE;
|
||||||
#else
|
#else
|
||||||
// Select and configure the DCMIPP source.
|
// Select and configure the DCMIPP source.
|
||||||
if (csi.mipi_if) {
|
if (csi->mipi_if) {
|
||||||
DCMIPP_CSI_ConfTypeDef scfg = {
|
DCMIPP_CSI_ConfTypeDef scfg = {
|
||||||
.NumberOfLanes = DCMIPP_CSI_TWO_DATA_LANES,
|
.NumberOfLanes = DCMIPP_CSI_TWO_DATA_LANES,
|
||||||
.DataLaneMapping = DCMIPP_CSI_PHYSICAL_DATA_LANES,
|
.DataLaneMapping = DCMIPP_CSI_PHYSICAL_DATA_LANES,
|
||||||
.PHYBitrate = (csi.mipi_brate == 850) ? DCMIPP_CSI_PHY_BT_850 : DCMIPP_CSI_PHY_BT_1200,
|
.PHYBitrate = (csi->mipi_brate == 850) ? DCMIPP_CSI_PHY_BT_850 : DCMIPP_CSI_PHY_BT_1200,
|
||||||
};
|
};
|
||||||
if (HAL_DCMIPP_CSI_SetConfig(&csi.dcmi, &scfg) != HAL_OK) {
|
if (HAL_DCMIPP_CSI_SetConfig(&csi->dcmi, &scfg) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
// Configure CSI virtual channel and pipe.
|
// Configure CSI virtual channel and pipe.
|
||||||
@ -212,61 +200,60 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
.DataTypeIDA = DCMIPP_DT_RAW10,
|
.DataTypeIDA = DCMIPP_DT_RAW10,
|
||||||
.DataTypeIDB = DCMIPP_DT_RAW10,
|
.DataTypeIDB = DCMIPP_DT_RAW10,
|
||||||
};
|
};
|
||||||
if (HAL_DCMIPP_CSI_SetVCConfig(&csi.dcmi, DCMIPP_VIRTUAL_CHANNEL0,
|
if (HAL_DCMIPP_CSI_SetVCConfig(&csi->dcmi, DCMIPP_VIRTUAL_CHANNEL0,
|
||||||
DCMIPP_CSI_DT_BPP10) != HAL_OK) {
|
DCMIPP_CSI_DT_BPP10) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
if (HAL_DCMIPP_CSI_PIPE_SetConfig(&csi.dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
if (HAL_DCMIPP_CSI_PIPE_SetConfig(&csi->dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCMIPP_ParallelConfTypeDef scfg = {
|
DCMIPP_ParallelConfTypeDef scfg = {
|
||||||
.SynchroMode = DCMIPP_SYNCHRO_HARDWARE,
|
.SynchroMode = DCMIPP_SYNCHRO_HARDWARE,
|
||||||
.ExtendedDataMode = DCMIPP_INTERFACE_8BITS,
|
.ExtendedDataMode = DCMIPP_INTERFACE_8BITS,
|
||||||
.VSPolarity = csi.vsync_pol ? DCMIPP_VSPOLARITY_HIGH : DCMIPP_VSPOLARITY_LOW,
|
.VSPolarity = csi->vsync_pol ? DCMIPP_VSPOLARITY_HIGH : DCMIPP_VSPOLARITY_LOW,
|
||||||
.HSPolarity = csi.hsync_pol ? DCMIPP_HSPOLARITY_HIGH : DCMIPP_HSPOLARITY_LOW,
|
.HSPolarity = csi->hsync_pol ? DCMIPP_HSPOLARITY_HIGH : DCMIPP_HSPOLARITY_LOW,
|
||||||
.PCKPolarity = csi.pixck_pol ? DCMIPP_PCKPOLARITY_RISING : DCMIPP_PCKPOLARITY_FALLING,
|
.PCKPolarity = csi->pixck_pol ? DCMIPP_PCKPOLARITY_RISING : DCMIPP_PCKPOLARITY_FALLING,
|
||||||
};
|
};
|
||||||
if (csi.raw_output) {
|
if (csi->raw_output) {
|
||||||
scfg.Format = DCMIPP_FORMAT_RAW8;
|
scfg.Format = DCMIPP_FORMAT_RAW8;
|
||||||
} else if (csi.pixformat == PIXFORMAT_RGB565) {
|
} else if (csi->pixformat == PIXFORMAT_RGB565) {
|
||||||
scfg.Format = DCMIPP_FORMAT_RGB565;
|
scfg.Format = DCMIPP_FORMAT_RGB565;
|
||||||
scfg.SwapCycles = DCMIPP_SWAPCYCLES_ENABLE;
|
scfg.SwapCycles = DCMIPP_SWAPCYCLES_ENABLE;
|
||||||
} else if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
} else if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
scfg.Format = (csi.mono_bpp == 1) ? DCMIPP_FORMAT_MONOCHROME_8B : DCMIPP_FORMAT_YUV422;
|
scfg.Format = (csi->mono_bpp == 1) ? DCMIPP_FORMAT_MONOCHROME_8B : DCMIPP_FORMAT_YUV422;
|
||||||
} else {
|
} else {
|
||||||
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
if (HAL_DCMIPP_PARALLEL_SetConfig(&csi.dcmi, &scfg) != HAL_OK) {
|
if (HAL_DCMIPP_PARALLEL_SetConfig(&csi->dcmi, &scfg) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the pixel processing pipeline.
|
// Configure the pixel processing pipeline.
|
||||||
DCMIPP_PipeConfTypeDef pcfg = { .FrameRate = DCMIPP_FRAME_RATE_ALL };
|
DCMIPP_PipeConfTypeDef pcfg = { .FrameRate = DCMIPP_FRAME_RATE_ALL };
|
||||||
if (csi.pixformat == PIXFORMAT_RGB565) {
|
if (csi->pixformat == PIXFORMAT_RGB565) {
|
||||||
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_RGB565_1;
|
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_RGB565_1;
|
||||||
} else if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
} else if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_MONO_Y8_G8_1;
|
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_MONO_Y8_G8_1;
|
||||||
} else {
|
} else {
|
||||||
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
if (HAL_DCMIPP_PIPE_SetConfig(&csi.dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
if (HAL_DCMIPP_PIPE_SetConfig(&csi->dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap RGB enabled.
|
// Swap RGB enabled.
|
||||||
if (csi.yuv_swap) {
|
if (csi->yuv_swap) {
|
||||||
HAL_DCMIPP_PIPE_EnableYUVSwap(&csi.dcmi, DCMIPP_PIPE);
|
HAL_DCMIPP_PIPE_EnableYUVSwap(&csi->dcmi, DCMIPP_PIPE);
|
||||||
}
|
}
|
||||||
// Swap YUV if enabled.
|
// Swap YUV if enabled.
|
||||||
if (csi.rgb_swap) {
|
if (csi->rgb_swap) {
|
||||||
HAL_DCMIPP_PIPE_EnableRedBlueSwap(&csi.dcmi, DCMIPP_PIPE);
|
HAL_DCMIPP_PIPE_EnableRedBlueSwap(&csi->dcmi, DCMIPP_PIPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure debayer.
|
// Configure debayer.
|
||||||
if (csi.raw_output && csi.pixformat != PIXFORMAT_BAYER) {
|
if (csi->raw_output && csi->pixformat != PIXFORMAT_BAYER) {
|
||||||
|
|
||||||
DCMIPP_RawBayer2RGBConfTypeDef rawcfg = {
|
DCMIPP_RawBayer2RGBConfTypeDef rawcfg = {
|
||||||
.RawBayerType = DCMIPP_RAWBAYER_BGGR,
|
.RawBayerType = DCMIPP_RAWBAYER_BGGR,
|
||||||
.VLineStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
.VLineStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
@ -274,8 +261,9 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
.PeakStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
.PeakStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
.EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
.EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
};
|
};
|
||||||
if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(&csi.dcmi, DCMIPP_PIPE, &rawcfg) != HAL_OK ||
|
|
||||||
HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&csi.dcmi, DCMIPP_PIPE) != HAL_OK) {
|
if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(&csi->dcmi, DCMIPP_PIPE, &rawcfg) != HAL_OK ||
|
||||||
|
HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&csi->dcmi, DCMIPP_PIPE) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,8 +276,8 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
.MultiplierBlue = 128,
|
.MultiplierBlue = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi.dcmi, DCMIPP_PIPE, &expcfg) != HAL_OK ||
|
if (HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmi, DCMIPP_PIPE, &expcfg) != HAL_OK ||
|
||||||
HAL_DCMIPP_PIPE_EnableISPExposure(&csi.dcmi, DCMIPP_PIPE) != HAL_OK) {
|
HAL_DCMIPP_PIPE_EnableISPExposure(&csi->dcmi, DCMIPP_PIPE) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,13 +295,13 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) {
|
for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) {
|
||||||
if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(&csi.dcmi,
|
if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(&csi->dcmi,
|
||||||
DCMIPP_PIPE, i,
|
DCMIPP_PIPE, i,
|
||||||
&statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) {
|
&statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(&csi.dcmi, DCMIPP_PIPE, i) != HAL_OK) {
|
if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(&csi->dcmi, DCMIPP_PIPE, i) != HAL_OK) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,73 +312,74 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the DCMI from generating more DMA requests, and disable the DMA.
|
// Stop the DCMI from generating more DMA requests, and disable the DMA.
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
static int stm_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
if (DCMI_IS_ACTIVE()) {
|
if (!DCMI_IS_ACTIVE()) {
|
||||||
#if USE_DCMI
|
return 0;
|
||||||
DCMI->CR &= ~DCMI_CR_ENABLE;
|
|
||||||
#endif
|
|
||||||
#if USE_DMA
|
|
||||||
if (in_irq) {
|
|
||||||
HAL_DMA_Abort_IT(&csi->dma);
|
|
||||||
} else {
|
|
||||||
HAL_DMA_Abort(&csi->dma);
|
|
||||||
}
|
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
|
||||||
#endif
|
|
||||||
#if USE_MDMA
|
|
||||||
if (!in_irq) {
|
|
||||||
HAL_MDMA_Abort(&csi->mdma0);
|
|
||||||
HAL_MDMA_Abort(&csi->mdma1);
|
|
||||||
}
|
|
||||||
HAL_MDMA_DeInit(&csi->mdma0);
|
|
||||||
HAL_MDMA_DeInit(&csi->mdma1);
|
|
||||||
#endif
|
|
||||||
#if USE_DCMI
|
|
||||||
__HAL_DCMI_DISABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
|
||||||
__HAL_DCMI_CLEAR_FLAG(&csi->dcmi, DCMI_FLAG_FRAMERI);
|
|
||||||
#else
|
|
||||||
if (!csi->mipi_if) {
|
|
||||||
HAL_DCMIPP_PIPE_Stop(&csi->dcmi, DCMIPP_PIPE);
|
|
||||||
} else {
|
|
||||||
HAL_DCMIPP_CSI_PIPE_Stop(&csi->dcmi, DCMIPP_PIPE, DCMIPP_VIRTUAL_CHANNEL0);
|
|
||||||
}
|
|
||||||
for (size_t i=0; i<DCMIPP_NUM_OF_PIPES; i++) {
|
|
||||||
csi->dcmi.PipeState[i] = HAL_DCMIPP_PIPE_STATE_RESET;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
csi->first_line = false;
|
|
||||||
csi->drop_frame = false;
|
|
||||||
csi->last_frame_ms = 0;
|
|
||||||
csi->last_frame_ms_valid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csi->fb) {
|
#if USE_DCMI
|
||||||
if (fifo_flush) {
|
DCMI->CR &= ~DCMI_CR_ENABLE;
|
||||||
framebuffer_flush_buffers(csi->fb, true);
|
#endif
|
||||||
} else if (!csi->disable_full_flush) {
|
|
||||||
framebuffer_flush_buffers(csi->fb, false);
|
#if USE_DMA
|
||||||
}
|
if (in_irq) {
|
||||||
|
HAL_DMA_Abort_IT(&csi->dma);
|
||||||
|
} else {
|
||||||
|
HAL_DMA_Abort(&csi->dma);
|
||||||
}
|
}
|
||||||
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MDMA
|
||||||
|
if (!in_irq) {
|
||||||
|
HAL_MDMA_Abort(&csi->mdma0);
|
||||||
|
HAL_MDMA_Abort(&csi->mdma1);
|
||||||
|
}
|
||||||
|
HAL_MDMA_DeInit(&csi->mdma0);
|
||||||
|
HAL_MDMA_DeInit(&csi->mdma1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
|
__HAL_DCMI_DISABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
||||||
|
__HAL_DCMI_CLEAR_FLAG(&csi->dcmi, DCMI_FLAG_FRAMERI);
|
||||||
|
#else
|
||||||
|
if (!csi->mipi_if) {
|
||||||
|
HAL_DCMIPP_PIPE_Stop(&csi->dcmi, DCMIPP_PIPE);
|
||||||
|
} else {
|
||||||
|
HAL_DCMIPP_CSI_PIPE_Stop(&csi->dcmi, DCMIPP_PIPE, DCMIPP_VIRTUAL_CHANNEL0);
|
||||||
|
}
|
||||||
|
for (size_t i=0; i<DCMIPP_NUM_OF_PIPES; i++) {
|
||||||
|
csi->dcmi.PipeState[i] = HAL_DCMIPP_PIPE_STATE_RESET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t omv_csi_get_clk_frequency() {
|
uint32_t omv_csi_get_clk_frequency() {
|
||||||
return (OMV_CSI_TIM_PCLK_FREQ() * 2) / (csi.tim.Init.Period + 1);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
|
||||||
|
if (!csi->tim.Instance) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (OMV_CSI_TIM_PCLK_FREQ() * 2) / (csi->tim.Init.Period + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO save frequency.
|
||||||
int omv_csi_set_clk_frequency(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 (csi->tim.Init.Period) {
|
||||||
HAL_TIM_PWM_Stop(&csi.tim, OMV_CSI_TIM_CHANNEL);
|
HAL_TIM_PWM_Stop(&csi->tim, OMV_CSI_TIM_CHANNEL);
|
||||||
HAL_TIM_PWM_DeInit(&csi.tim);
|
HAL_TIM_PWM_DeInit(&csi->tim);
|
||||||
memset(&csi.tim, 0, sizeof(csi.tim));
|
memset(&csi->tim, 0, sizeof(csi->tim));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
csi.tim.Instance = OMV_CSI_TIM;
|
csi->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;
|
||||||
@ -399,20 +388,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 (csi->tim.Init.Period && (csi->tim.Init.Period != period)) {
|
||||||
// __HAL_TIM_SET_AUTORELOAD sets csi.tim.Init.Period...
|
// __HAL_TIM_SET_AUTORELOAD sets csi->tim.Init.Period...
|
||||||
__HAL_TIM_SET_AUTORELOAD(&csi.tim, period);
|
__HAL_TIM_SET_AUTORELOAD(&csi->tim, period);
|
||||||
__HAL_TIM_SET_COMPARE(&csi.tim, OMV_CSI_TIM_CHANNEL, pulse);
|
__HAL_TIM_SET_COMPARE(&csi->tim, OMV_CSI_TIM_CHANNEL, pulse);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Timer base configuration */
|
/* Timer base configuration */
|
||||||
csi.tim.Init.Period = period;
|
csi->tim.Init.Period = period;
|
||||||
csi.tim.Init.Prescaler = 0;
|
csi->tim.Init.Prescaler = 0;
|
||||||
csi.tim.Init.CounterMode = TIM_COUNTERMODE_UP;
|
csi->tim.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
csi.tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
csi->tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
csi.tim.Init.RepetitionCounter = 0;
|
csi->tim.Init.RepetitionCounter = 0;
|
||||||
csi.tim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
csi->tim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||||
|
|
||||||
/* Timer channel configuration */
|
/* Timer channel configuration */
|
||||||
TIM_OC_InitTypeDef TIMOCHandle;
|
TIM_OC_InitTypeDef TIMOCHandle;
|
||||||
@ -424,9 +413,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(&csi->tim) != HAL_OK)
|
||||||
|| (HAL_TIM_PWM_ConfigChannel(&csi.tim, &TIMOCHandle, OMV_CSI_TIM_CHANNEL) != HAL_OK)
|
|| (HAL_TIM_PWM_ConfigChannel(&csi->tim, &TIMOCHandle, OMV_CSI_TIM_CHANNEL) != HAL_OK)
|
||||||
|| (HAL_TIM_PWM_Start(&csi.tim, OMV_CSI_TIM_CHANNEL) != HAL_OK)) {
|
|| (HAL_TIM_PWM_Start(&csi->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)
|
||||||
@ -442,13 +431,13 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_shutdown(int enable) {
|
int omv_csi_shutdown(omv_csi_t *csi, int enable) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
omv_csi_abort(&csi, true, false);
|
omv_csi_abort(csi, true, false);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
#if defined(OMV_CSI_POWER_PIN)
|
#if defined(OMV_CSI_POWER_PIN)
|
||||||
if (csi.power_pol == OMV_CSI_ACTIVE_HIGH) {
|
if (csi->power_pol == OMV_CSI_ACTIVE_HIGH) {
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
||||||
} else {
|
} else {
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
||||||
@ -456,39 +445,32 @@ int omv_csi_shutdown(int enable) {
|
|||||||
#endif
|
#endif
|
||||||
#if USE_DCMI
|
#if USE_DCMI
|
||||||
HAL_NVIC_DisableIRQ(DCMI_IRQn);
|
HAL_NVIC_DisableIRQ(DCMI_IRQn);
|
||||||
HAL_DCMI_DeInit(&csi.dcmi);
|
HAL_DCMI_DeInit(&csi->dcmi);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(OMV_CSI_POWER_PIN)
|
#if defined(OMV_CSI_POWER_PIN)
|
||||||
if (csi.power_pol == OMV_CSI_ACTIVE_HIGH) {
|
if (csi->power_pol == OMV_CSI_ACTIVE_HIGH) {
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
||||||
} else {
|
} else {
|
||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret = omv_csi_config(OMV_CSI_CONFIG_INIT);
|
ret = omv_csi_config(csi, OMV_CSI_CONFIG_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_hal_delay_ms(10);
|
mp_hal_delay_ms(10);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omv_csi_vsync_callback(void *data) {
|
int omv_csi_set_vsync_callback(omv_csi_t *csi, omv_csi_cb_t cb) {
|
||||||
if (csi.vsync_callback != NULL) {
|
if (cb.fun == NULL) {
|
||||||
csi.vsync_callback(omv_gpio_read(OMV_CSI_VSYNC_PIN));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_set_vsync_callback(vsync_cb_t vsync_cb) {
|
|
||||||
csi.vsync_callback = vsync_cb;
|
|
||||||
if (csi.vsync_callback == NULL) {
|
|
||||||
#if (DCMI_VSYNC_EXTI_SHARED == 0)
|
#if (DCMI_VSYNC_EXTI_SHARED == 0)
|
||||||
// Disable VSYNC EXTI IRQ
|
// Disable VSYNC EXTI IRQ
|
||||||
omv_gpio_irq_enable(OMV_CSI_VSYNC_PIN, false);
|
omv_gpio_irq_enable(OMV_CSI_VSYNC_PIN, false);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// Enable VSYNC EXTI IRQ
|
// Enable VSYNC EXTI IRQ
|
||||||
omv_gpio_irq_register(OMV_CSI_VSYNC_PIN, omv_csi_vsync_callback, NULL);
|
omv_gpio_irq_register(OMV_CSI_VSYNC_PIN, cb.fun, cb.arg);
|
||||||
omv_gpio_irq_enable(OMV_CSI_VSYNC_PIN, true);
|
omv_gpio_irq_enable(OMV_CSI_VSYNC_PIN, true);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -498,17 +480,16 @@ int omv_csi_set_vsync_callback(vsync_cb_t vsync_cb) {
|
|||||||
// If the image is cropped by more than 1 word in width, align the line start to a word
|
// If the image is cropped by more than 1 word in width, align the line start to a word
|
||||||
// address to improve copy performance. Do not crop by more than 1 word as this will
|
// address to improve copy performance. Do not crop by more than 1 word as this will
|
||||||
// result in less time between DMA transfers complete interrupts on 16-byte boundaries.
|
// result in less time between DMA transfers complete interrupts on 16-byte boundaries.
|
||||||
static uint32_t get_dcmi_hw_crop(uint32_t bytes_per_pixel) {
|
static uint32_t get_dcmi_hw_crop(omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
||||||
framebuffer_t *fb = csi.fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
uint32_t byte_x_offset = (fb->x * bytes_per_pixel) % sizeof(uint32_t);
|
uint32_t byte_x_offset = (fb->x * bytes_per_pixel) % sizeof(uint32_t);
|
||||||
uint32_t width_remainder = (resolution[csi.framesize][0] - (fb->x + fb->u)) * bytes_per_pixel;
|
uint32_t width_remainder = (resolution[csi->framesize][0] - (fb->x + fb->u)) * bytes_per_pixel;
|
||||||
uint32_t x_crop = 0;
|
|
||||||
|
|
||||||
if (byte_x_offset && (width_remainder >= (sizeof(uint32_t) - byte_x_offset))) {
|
if (byte_x_offset && (width_remainder >= (sizeof(uint32_t) - byte_x_offset))) {
|
||||||
x_crop = byte_x_offset;
|
return byte_x_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x_crop;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -517,7 +498,9 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
#else
|
#else
|
||||||
void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe) {
|
void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe) {
|
||||||
#endif
|
#endif
|
||||||
framebuffer_t *fb = csi.fb;
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
// Clear out any stale flags.
|
// Clear out any stale flags.
|
||||||
DMA2->LIFCR = DMA_FLAG_TCIF1_5 | DMA_FLAG_HTIF1_5;
|
DMA2->LIFCR = DMA_FLAG_TCIF1_5 | DMA_FLAG_HTIF1_5;
|
||||||
@ -526,9 +509,9 @@ void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t p
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset DCMI_DMAConvCpltUser frame drop state.
|
// Reset DCMI_DMAConvCpltUser frame drop state.
|
||||||
csi.first_line = false;
|
csi->first_line = false;
|
||||||
if (csi.drop_frame) {
|
if (csi->drop_frame) {
|
||||||
csi.drop_frame = false;
|
csi->drop_frame = false;
|
||||||
// Reset the buffer's state if the frame was dropped.
|
// Reset the buffer's state if the frame was dropped.
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
@ -539,15 +522,15 @@ void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t p
|
|||||||
|
|
||||||
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||||
|
|
||||||
if (csi.frame_callback) {
|
if (csi->frame_cb.fun) {
|
||||||
csi.frame_callback();
|
csi->frame_cb.fun(csi->frame_cb.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_DCMIPP
|
#if USE_DCMIPP
|
||||||
// Get the destination buffer address.
|
// Get the destination buffer address.
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
omv_csi_abort(&csi, false, false);
|
omv_csi_abort(csi, false, false);
|
||||||
} else {
|
} else {
|
||||||
HAL_DCMIPP_PIPE_SetMemoryAddress(dcmipp, pipe, DCMIPP_MEMORY_ADDRESS_0, (uint32_t) buffer->data);
|
HAL_DCMIPP_PIPE_SetMemoryAddress(dcmipp, pipe, DCMIPP_MEMORY_ADDRESS_0, (uint32_t) buffer->data);
|
||||||
}
|
}
|
||||||
@ -560,14 +543,15 @@ void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t p
|
|||||||
// Using line buffers allows performing post-processing before writing the frame to the
|
// Using line buffers allows performing post-processing before writing the frame to the
|
||||||
// framebuffer, and help hide external RAM latency.
|
// framebuffer, and help hide external RAM latency.
|
||||||
void DCMI_DMAConvCpltUser(uint32_t addr) {
|
void DCMI_DMAConvCpltUser(uint32_t addr) {
|
||||||
framebuffer_t *fb = csi.fb;
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Throttle frames to match the current frame rate.
|
// Throttle frames to match the current frame rate.
|
||||||
omv_csi_throttle_framerate();
|
omv_csi_throttle_framerate(csi);
|
||||||
|
|
||||||
if (csi.drop_frame) {
|
if (csi->drop_frame) {
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
if (!csi.transpose) {
|
if (!csi->transpose) {
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -576,17 +560,17 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
|
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
omv_csi_abort(&csi, false, true);
|
omv_csi_abort(csi, false, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_JPEG) {
|
if (csi->pixformat == PIXFORMAT_JPEG) {
|
||||||
if (csi.jpg_format == 3) {
|
if (csi->jpg_format == 3) {
|
||||||
// JPEG MODE 3: Variable line width per frame, with the last line potentially shorter and
|
// JPEG MODE 3: Variable line width per frame, with the last line potentially shorter and
|
||||||
// no padding. `offset` is incremented once every max transfer, and the DMA counter holds
|
// no padding. `offset` is incremented once every max transfer, and the DMA counter holds
|
||||||
// the total size.
|
// the total size.
|
||||||
buffer->offset += 1;
|
buffer->offset += 1;
|
||||||
} else if (csi.jpg_format == 4) {
|
} else if (csi->jpg_format == 4) {
|
||||||
// JPEG MODE 4: Fixed width and height per frame. Each line starts with two bytes indicating
|
// JPEG MODE 4: Fixed width and height per frame. Each line starts with two bytes indicating
|
||||||
// valid data length, followed by image data and optional padding (0xFF). `offset` holds the
|
// valid data length, followed by image data and optional padding (0xFF). `offset` holds the
|
||||||
// total size.
|
// total size.
|
||||||
@ -604,41 +588,41 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
// DCMI_DMAConvCpltUser is called with the other MAR register.
|
// DCMI_DMAConvCpltUser is called with the other MAR register.
|
||||||
// So, we have to fix the address in full MDMA offload mode.
|
// So, we have to fix the address in full MDMA offload mode.
|
||||||
if (!csi.transpose) {
|
if (!csi->transpose) {
|
||||||
addr = (uint32_t) &_line_buf;
|
addr = (uint32_t) &_line_buf;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint8_t *src = ((uint8_t *) addr) + (fb->x * bytes_per_pixel) - get_dcmi_hw_crop(bytes_per_pixel);
|
uint8_t *src = ((uint8_t *) addr) + (fb->x * bytes_per_pixel) - get_dcmi_hw_crop(csi, bytes_per_pixel);
|
||||||
uint8_t *dst = buffer->data;
|
uint8_t *dst = buffer->data;
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
bytes_per_pixel = sizeof(uint8_t);
|
bytes_per_pixel = sizeof(uint8_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all non-JPEG and non-transposed modes image capture can be completely offload to MDMA.
|
// For all non-JPEG and non-transposed modes image capture can be completely offload to MDMA.
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
if (!csi.transpose) {
|
if (!csi->transpose) {
|
||||||
// NOTE: MDMA is started here, not in FRAME/VSYNC callbacks, to maximize the time before
|
// NOTE: MDMA is started here, not in FRAME/VSYNC callbacks, to maximize the time before
|
||||||
// the frame has to be dropped.
|
// the frame has to be dropped.
|
||||||
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
||||||
// mdma0 will copy this line of the image to the final destination.
|
// mdma0 will copy this line of the image to the final destination.
|
||||||
__HAL_UNLOCK(&csi.mdma0);
|
__HAL_UNLOCK(&csi->mdma0);
|
||||||
csi.mdma0.State = HAL_MDMA_STATE_READY;
|
csi->mdma0.State = HAL_MDMA_STATE_READY;
|
||||||
HAL_MDMA_Start(&csi.mdma0, (uint32_t) src, (uint32_t) dst,
|
HAL_MDMA_Start(&csi->mdma0, (uint32_t) src, (uint32_t) dst,
|
||||||
line_width_bytes, 1);
|
line_width_bytes, 1);
|
||||||
// mdma1 will copy all remaining lines of the image to the final destination.
|
// mdma1 will copy all remaining lines of the image to the final destination.
|
||||||
__HAL_UNLOCK(&csi.mdma1);
|
__HAL_UNLOCK(&csi->mdma1);
|
||||||
csi.mdma1.State = HAL_MDMA_STATE_READY;
|
csi->mdma1.State = HAL_MDMA_STATE_READY;
|
||||||
HAL_MDMA_Start(&csi.mdma1, (uint32_t) src, (uint32_t) (dst + line_width_bytes),
|
HAL_MDMA_Start(&csi->mdma1, (uint32_t) src, (uint32_t) (dst + line_width_bytes),
|
||||||
line_width_bytes, fb->v - 1);
|
line_width_bytes, fb->v - 1);
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!csi.transpose) {
|
if (!csi->transpose) {
|
||||||
dst += fb->u * bytes_per_pixel * buffer->offset++;
|
dst += fb->u * bytes_per_pixel * buffer->offset++;
|
||||||
} else {
|
} else {
|
||||||
dst += bytes_per_pixel * buffer->offset++;
|
dst += bytes_per_pixel * buffer->offset++;
|
||||||
@ -646,9 +630,9 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
// Two MDMA channels are used to maximize the time available for each channel to finish the transfer.
|
// Two MDMA channels are used to maximize the time available for each channel to finish the transfer.
|
||||||
omv_csi_copy_line((buffer->offset % 2) ? &csi.mdma1 : &csi.mdma0, src, dst);
|
omv_csi_copy_line(csi, (buffer->offset % 2) ? &csi->mdma1 : &csi->mdma0, src, dst);
|
||||||
#else
|
#else
|
||||||
omv_csi_copy_line(NULL, src, dst);
|
omv_csi_copy_line(csi, NULL, src, dst);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -676,7 +660,7 @@ static void omv_csi_mdma_config(omv_csi_t *csi, MDMA_InitTypeDef *init, uint32_t
|
|||||||
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
|
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t line_offset_bytes = (fb->x * bytes_per_pixel) - get_dcmi_hw_crop(bytes_per_pixel);
|
uint32_t line_offset_bytes = (fb->x * bytes_per_pixel) - get_dcmi_hw_crop(csi, bytes_per_pixel);
|
||||||
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
||||||
|
|
||||||
if (csi->transpose) {
|
if (csi->transpose) {
|
||||||
@ -750,13 +734,13 @@ static void omv_csi_mdma_enable(omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
|
int omv_csi_dma_memcpy(omv_csi_t *csi, void *dma, void *dst, void *src, int bpp, bool transposed) {
|
||||||
framebuffer_t *fb = csi.fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
MDMA_HandleTypeDef *handle = dma;
|
MDMA_HandleTypeDef *handle = dma;
|
||||||
|
|
||||||
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
||||||
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
||||||
csi.drop_frame = true;
|
csi->drop_frame = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,7 +777,7 @@ void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) {
|
|||||||
//printf("Luminance: %f AVG_R: %lu, AVG_G: %lu, AVG_B: %lu\n", (double) luminance, avg[0], avg[1], avg[2]);
|
//printf("Luminance: %f AVG_R: %lu, AVG_G: %lu, AVG_B: %lu\n", (double) luminance, avg[0], avg[1], avg[2]);
|
||||||
|
|
||||||
if (csi->ioctl) {
|
if (csi->ioctl) {
|
||||||
omv_csi_ioctl(OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance));
|
omv_csi_ioctl(csi, OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate average and exposure factors for each channel (R, G, B)
|
// Calculate average and exposure factors for each channel (R, G, B)
|
||||||
@ -820,8 +804,7 @@ void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
@ -835,11 +818,13 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
|
|
||||||
// Compress the framebuffer for the IDE preview, if not the first frame, the
|
// Compress the framebuffer for the IDE preview, if not the first frame, the
|
||||||
// framebuffer is enabled, and the image sensor doesn't support JPEG encoding.
|
// framebuffer is enabled, and the image sensor doesn't support JPEG encoding.
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
if (flags & OMV_CSI_CAPTURE_FLAGS_UPDATE) {
|
||||||
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the raw frame fits into the FB. It will be switched from RGB565 to BAYER
|
// Ensure that the raw frame fits into the FB. It will be switched from RGB565 to BAYER
|
||||||
// first to save space before being cropped until it fits.
|
// first to save space before being cropped until it fits.
|
||||||
omv_csi_auto_crop_framebuffer();
|
omv_csi_auto_crop_framebuffer(csi);
|
||||||
|
|
||||||
// Restore frame buffer width and height if they were changed before. BPP is restored later.
|
// Restore frame buffer width and height if they were changed before. BPP is restored later.
|
||||||
// Note that JPEG compression is done first on the framebuffer with the user settings.
|
// Note that JPEG compression is done first on the framebuffer with the user settings.
|
||||||
@ -864,8 +849,8 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
|
|
||||||
#if USE_DCMI
|
#if USE_DCMI
|
||||||
// Setup the size and address of the transfer
|
// Setup the size and address of the transfer
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp(csi);
|
||||||
uint32_t x_crop = get_dcmi_hw_crop(bytes_per_pixel);
|
uint32_t x_crop = get_dcmi_hw_crop(csi, bytes_per_pixel);
|
||||||
uint32_t line_width_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
uint32_t line_width_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
||||||
|
|
||||||
// Shrink the captured pixel count by one word to allow cropping to fix alignment.
|
// Shrink the captured pixel count by one word to allow cropping to fix alignment.
|
||||||
@ -928,7 +913,7 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
(uint32_t) &_line_buf, length / sizeof(uint32_t), h);
|
(uint32_t) &_line_buf, length / sizeof(uint32_t), h);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_dst_bpp();
|
uint32_t bytes_per_pixel = omv_csi_get_dst_bpp(csi);
|
||||||
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
||||||
|
|
||||||
if (!line_width_bytes ||
|
if (!line_width_bytes ||
|
||||||
@ -1089,7 +1074,8 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int ret = 0;
|
||||||
|
static omv_i2c_t i2c;
|
||||||
|
|
||||||
// List of I2C buses to scan.
|
// List of I2C buses to scan.
|
||||||
uint32_t buses[][2] = {
|
uint32_t buses[][2] = {
|
||||||
@ -1099,47 +1085,54 @@ int omv_csi_init() {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->abort = stm_csi_abort;
|
||||||
csi.i2c = &csi_i2c;
|
csi->config = stm_csi_config;
|
||||||
|
csi->snapshot = stm_csi_snapshot;
|
||||||
// Set default snapshot function.
|
csi->color_palette = rainbow_table;
|
||||||
csi.snapshot = omv_csi_snapshot;
|
}
|
||||||
|
|
||||||
// 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(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// 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++) {
|
||||||
uint32_t id = buses[i][0], speed = buses[i][1];
|
// Initialize the camera bus.
|
||||||
if ((init_ret = omv_csi_probe_init(id, speed)) == 0) {
|
omv_i2c_init(&i2c, buses[i][0], buses[i][1]);
|
||||||
|
|
||||||
|
if (!(ret = omv_csi_probe(&i2c))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
omv_i2c_deinit(csi.i2c);
|
|
||||||
|
omv_i2c_deinit(&i2c);
|
||||||
|
|
||||||
// Scan the next bus or fail if this is the last one.
|
// Scan the next bus or fail if this is the last one.
|
||||||
if ((i + 1) == n_buses) {
|
if ((i + 1) == n_buses) {
|
||||||
return init_ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the DCMI interface.
|
// Configure the DCMI interface.
|
||||||
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
csi->detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear fb_enabled flag.
|
// Clear fb_enabled flag.
|
||||||
JPEG_FB()->enabled = 0;
|
JPEG_FB()->enabled = 0;
|
||||||
|
|
||||||
// Set default color palette.
|
|
||||||
csi.color_palette = rainbow_table;
|
|
||||||
|
|
||||||
csi.detected = true;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user