Compare commits

...

7 commits

Author SHA1 Message Date
lady ada
f33a3a656e move firmware to bin file 2021-10-17 17:27:18 -04:00
lady ada
ab3c5809ae autofocus working 2021-10-17 17:02:49 -04:00
lady ada
dd3d3e4117 add strobe/LED support! (note NOT ALL CAMS HAVE THIS PIN CONNECTED UP!) 2021-10-17 00:37:06 -04:00
lady ada
4464ea41e3 valval 2021-10-16 22:59:59 -04:00
lady ada
934c6e5190 tweak startup 2021-10-16 22:58:36 -04:00
lady ada
ee91db69c5 add sekret test modes 2021-10-16 22:57:33 -04:00
lady ada
e75648fa5e add powerdown (reduce current greatly) 2021-10-16 22:43:13 -04:00
2 changed files with 149 additions and 17 deletions

View file

@ -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

Binary file not shown.