diff --git a/adafruit_ov5640.py b/adafruit_ov5640.py index 95cdad6..5b43bc2 100644 --- a/adafruit_ov5640.py +++ b/adafruit_ov5640.py @@ -99,6 +99,21 @@ # 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 @@ 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 @@ def _write_list(self, reg_list): 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,31 +880,38 @@ def __init__( i2c_address (int): The I2C address of the camera. """ - # Initialize the master clock - if mclk: - self._mclk_pwm = pwmio.PWMOut(mclk, frequency=mclk_frequency) - self._mclk_pwm.duty_cycle = 32768 - else: - self._mclk_pwm = None - + # we're supposed to go into shutdown if we can, first if shutdown: self._shutdown = digitalio.DigitalInOut(shutdown) self._shutdown.switch_to_output(True) - time.sleep(0.1) - self._shutdown.switch_to_output(False) - time.sleep(0.3) else: self._shutdown = None if reset: self._reset = digitalio.DigitalInOut(reset) self._reset.switch_to_output(False) - time.sleep(0.1) - self._reset.switch_to_output(True) - time.sleep(0.1) else: self._reset = None + time.sleep(0.1) + + # Initialize the master clock + if mclk: + self._mclk_pwm = pwmio.PWMOut(mclk, frequency=mclk_frequency) + self._mclk_pwm.duty_cycle = 32768 + else: + self._mclk_pwm = None + + if self._shutdown: + self._shutdown.switch_to_output(False) + time.sleep(0.1) + + + if self._reset: + self._reset.switch_to_output(True) + + 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 @@ def __init__( 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 @@ def deinit(self): self._shutdown.deinit() if self._reset: self._reset.deinit() + self.powerdown = True @property def size(self): @@ -1131,9 +1174,12 @@ def test_pattern(self): 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 @@ def night_mode(self): @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 diff --git a/examples/ov5640_autofocus.bin b/examples/ov5640_autofocus.bin new file mode 100644 index 0000000..06e4b5a Binary files /dev/null and b/examples/ov5640_autofocus.bin differ