Compare commits
7 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f33a3a656e | ||
|
|
ab3c5809ae | ||
|
|
dd3d3e4117 | ||
|
|
4464ea41e3 | ||
|
|
934c6e5190 | ||
|
|
ee91db69c5 | ||
|
|
e75648fa5e |
2 changed files with 149 additions and 17 deletions
|
|
@ -99,6 +99,21 @@ _AEC_PK_MANUAL = const(0x3503)
|
|||
|
||||
# gain = {0x350A[1:0], 0x350B[7:0]} / 16
|
||||
|
||||
_STROBE_CTRL = const(0x3b00)
|
||||
_FREX_MODE = const(0x3b07)
|
||||
_FREX_REQUEST = const(0x3B08)
|
||||
_PAD_OUTPUT_ENABLE00 = const(0x3016)
|
||||
_PAD_OUTPUT_VALUE00 = const(0x3019)
|
||||
_PAD_SELECT00 = const(0x301C)
|
||||
|
||||
FREX_MODE_0 = 1
|
||||
FREX_MODE_1 = 2
|
||||
FREX_MODE_ROLL = 3
|
||||
|
||||
STROBE_MODE_XENON = 0
|
||||
STROBE_MODE_LED1 = 1
|
||||
STROBE_MODE_LED2 = 2
|
||||
STROBE_MODE_LED3 = 3
|
||||
|
||||
_X_ADDR_ST_H = const(0x3800)
|
||||
# Bit[3:0]: X address start[11:8]
|
||||
|
|
@ -707,6 +722,25 @@ sensor_regs_awb0 = [
|
|||
0x519D, 0x82,
|
||||
0x519E, 0x38,
|
||||
]
|
||||
|
||||
_autofocus_firmware_load = (
|
||||
0x3022, 0x00,
|
||||
0x3023, 0x00,
|
||||
0x3024, 0x00,
|
||||
0x3025, 0x00,
|
||||
0x3026, 0x00,
|
||||
0x3027, 0x00,
|
||||
0x3028, 0x00,
|
||||
0x3029, 0x7f,
|
||||
0x3000, 0x00,
|
||||
)
|
||||
|
||||
AUTOFOCUS_STAT_FIRMWAREBAD = 0x7F
|
||||
AUTOFOCUS_STAT_STARTUP = 0x7E
|
||||
AUTOFOCUS_STAT_IDLE = 0x70
|
||||
AUTOFOCUS_STAT_FOCUSING = 0x00
|
||||
AUTOFOCUS_STAT_FOCUSED = 0x10
|
||||
|
||||
# fmt: on
|
||||
|
||||
|
||||
|
|
@ -797,7 +831,7 @@ class _SCCB16CameraBase: # pylint: disable=too-few-public-methods
|
|||
self._write_register(register, value)
|
||||
|
||||
def _write_reg_bits(self, reg, mask, enable):
|
||||
val = val = self._read_register(reg)
|
||||
val = self._read_register(reg)
|
||||
if enable:
|
||||
val |= mask
|
||||
else:
|
||||
|
|
@ -846,6 +880,21 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
i2c_address (int): The I2C address of the camera.
|
||||
"""
|
||||
|
||||
# we're supposed to go into shutdown if we can, first
|
||||
if shutdown:
|
||||
self._shutdown = digitalio.DigitalInOut(shutdown)
|
||||
self._shutdown.switch_to_output(True)
|
||||
else:
|
||||
self._shutdown = None
|
||||
|
||||
if reset:
|
||||
self._reset = digitalio.DigitalInOut(reset)
|
||||
self._reset.switch_to_output(False)
|
||||
else:
|
||||
self._reset = None
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
# Initialize the master clock
|
||||
if mclk:
|
||||
self._mclk_pwm = pwmio.PWMOut(mclk, frequency=mclk_frequency)
|
||||
|
|
@ -853,23 +902,15 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
else:
|
||||
self._mclk_pwm = None
|
||||
|
||||
if shutdown:
|
||||
self._shutdown = digitalio.DigitalInOut(shutdown)
|
||||
self._shutdown.switch_to_output(True)
|
||||
time.sleep(0.1)
|
||||
if self._shutdown:
|
||||
self._shutdown.switch_to_output(False)
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
self._shutdown = None
|
||||
time.sleep(0.1)
|
||||
|
||||
if reset:
|
||||
self._reset = digitalio.DigitalInOut(reset)
|
||||
self._reset.switch_to_output(False)
|
||||
time.sleep(0.1)
|
||||
|
||||
if self._reset:
|
||||
self._reset.switch_to_output(True)
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
self._reset = None
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
# Now that the master clock is running, we can initialize i2c comms
|
||||
super().__init__(i2c_bus, i2c_address)
|
||||
|
|
@ -892,6 +933,7 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
self._ev = 0
|
||||
self._white_balance = 0
|
||||
self.size = size
|
||||
self._strobe_enabled = False
|
||||
|
||||
chip_id = _RegBits16(_CHIP_ID_HIGH, 0, 0xFFFF)
|
||||
|
||||
|
|
@ -1009,6 +1051,7 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
self._shutdown.deinit()
|
||||
if self._reset:
|
||||
self._reset.deinit()
|
||||
self.powerdown = True
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
|
|
@ -1131,9 +1174,12 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
return self._test_pattern
|
||||
|
||||
@test_pattern.setter
|
||||
def test_pattern(self, value: bool) -> None:
|
||||
def test_pattern(self, value) -> None:
|
||||
if type(value) is bool:
|
||||
self._write_register(_PRE_ISP_TEST_SETTING_1, value << 7)
|
||||
else:
|
||||
self._write_register(_PRE_ISP_TEST_SETTING_1, 1 << 7 | value)
|
||||
self._test_pattern = value
|
||||
self._write_register(_PRE_ISP_TEST_SETTING_1, value << 7)
|
||||
|
||||
@property
|
||||
def saturation(self):
|
||||
|
|
@ -1259,3 +1305,89 @@ class OV5640(_SCCB16CameraBase): # pylint: disable=too-many-instance-attributes
|
|||
@night_mode.setter
|
||||
def night_mode(self, value):
|
||||
self._write_reg_bits(0x3A00, 0x04, value)
|
||||
|
||||
@property
|
||||
def powerdown(self):
|
||||
return bool(self._read_register(_SYSTEM_CTROL0) & 0x40)
|
||||
|
||||
@powerdown.setter
|
||||
def powerdown(self, value):
|
||||
self._write_reg_bits(_SYSTEM_CTROL0, 0x40, bool(value))
|
||||
|
||||
def strobe_config(self, enabled, pulse_invert, frex_mode, strobe_mode):
|
||||
# set the FREX mode rolling
|
||||
if frex_mode not in (FREX_MODE_0, FREX_MODE_1, FREX_MODE_ROLL):
|
||||
raise ValueError("Frex mode must be 0, 1 or 2 (rolling)")
|
||||
self._write_register(_FREX_MODE, frex_mode)
|
||||
# set the output pin
|
||||
self._write_register(_PAD_OUTPUT_ENABLE00, 0x2)
|
||||
# set the pulse invert, mode and enable
|
||||
if strobe_mode not in (STROBE_MODE_XENON, STROBE_MODE_LED1, STROBE_MODE_LED2, STROBE_MODE_LED3):
|
||||
raise ValueError("Strobe mode must be 0~3")
|
||||
self._write_register(_STROBE_CTRL,
|
||||
(bool(enabled) << 7) |
|
||||
(bool(pulse_invert) << 6) |
|
||||
(strobe_mode & 0x3))
|
||||
|
||||
#print("strobe reg: ", hex(self._read_register(_STROBE_CTRL)))
|
||||
#print("pad00 reg: ", hex(self._read_register(_PAD_OUTPUT_ENABLE00)))
|
||||
#print("clock00 reg: ", hex(self._read_register(0x3004)))
|
||||
|
||||
@property
|
||||
def strobe_request(self):
|
||||
return bool(self._read_register(_FREX_REQUEST))
|
||||
|
||||
@strobe_request.setter
|
||||
def strobe_request(self, value):
|
||||
self._write_register(_FREX_REQUEST, bool(value))
|
||||
|
||||
@property
|
||||
def strobe_pin(self):
|
||||
return bool(self._read_register(_PAD_OUTPUT_VALUE00))
|
||||
|
||||
@strobe_pin.setter
|
||||
def strobe_pin(self, value):
|
||||
self._write_register(_PAD_OUTPUT_ENABLE00, 0x02)
|
||||
self._write_register(_PAD_SELECT00, 0x02)
|
||||
self._write_register(_PAD_OUTPUT_VALUE00, bool(value) << 1)
|
||||
|
||||
def autofocus_init(self, firmfilename):
|
||||
self._write_register(0x3000, 0x20) # reset
|
||||
with open(firmfilename, mode='rb') as file:
|
||||
firmware = file.read()
|
||||
for addr,val in enumerate(firmware):
|
||||
self._write_register(0x8000+addr, val)
|
||||
|
||||
self._write_list(_autofocus_firmware_load)
|
||||
for _ in range(100):
|
||||
if self.autofocus_status == AUTOFOCUS_STAT_IDLE:
|
||||
break
|
||||
time.sleep(0.01)
|
||||
else:
|
||||
raise RuntimeError("Timed out after trying to load autofocus firmware")
|
||||
return True
|
||||
|
||||
@property
|
||||
def autofocus_status(self):
|
||||
return self._read_register(0x3029)
|
||||
|
||||
def autofocus(self):
|
||||
self._write_register(0x3023, 0x01) # clear command ack
|
||||
self._write_register(0x3022, 0x08) # release focus
|
||||
for _ in range(100):
|
||||
if self._read_register(0x3032) == 0x0: # command is finished
|
||||
break
|
||||
time.sleep(0.01)
|
||||
else:
|
||||
raise RuntimeError("Timed out trying to run autofocus")
|
||||
|
||||
self._write_register(0x3023, 0x01)
|
||||
self._write_register(0x3022, 0x04)
|
||||
for _ in range(100):
|
||||
if self._read_register(0x3032) == 0x0: # command is finished
|
||||
break
|
||||
time.sleep(0.01)
|
||||
else:
|
||||
raise RuntimeError("Timed out trying to run autofocus")
|
||||
|
||||
return True
|
||||
|
|
|
|||
BIN
examples/ov5640_autofocus.bin
Normal file
BIN
examples/ov5640_autofocus.bin
Normal file
Binary file not shown.
Loading…
Reference in a new issue