25
25
"""
26
26
27
27
# pylint: disable=too-many-lines
28
-
28
+ # pylint: disable=too-many-public-methods
29
29
# imports
30
30
import time
31
31
import imagecapture
414
414
_REG_DLY = const (0xFFFF )
415
415
_REGLIST_TAIL = const (0x0000 )
416
416
417
+ _OV5640_STAT_FIRMWAREBAD = const (0x7F )
418
+ _OV5640_STAT_STARTUP = const (0x7E )
419
+ _OV5640_STAT_IDLE = const (0x70 )
420
+ _OV5640_STAT_FOCUSING = const (0x00 )
421
+ _OV5640_STAT_FOCUSED = const (0x10 )
422
+
423
+ _OV5640_CMD_TRIGGER_AUTOFOCUS = const (0x03 )
424
+ _OV5640_CMD_AUTO_AUTOFOCUS = const (0x04 )
425
+ _OV5640_CMD_RELEASE_FOCUS = const (0x08 )
426
+ _OV5640_CMD_AF_SET_VCM_STEP = const (0x1A )
427
+ _OV5640_CMD_AF_GET_VCM_STEP = const (0x1B )
428
+
429
+ _OV5640_CMD_MAIN = const (0x3022 )
430
+ _OV5640_CMD_ACK = const (0x3023 )
431
+ _OV5640_CMD_PARA0 = const (0x3024 )
432
+ _OV5640_CMD_PARA1 = const (0x3025 )
433
+ _OV5640_CMD_PARA2 = const (0x3026 )
434
+ _OV5640_CMD_PARA3 = const (0x3027 )
435
+ _OV5640_CMD_PARA4 = const (0x3028 )
436
+ _OV5640_CMD_FW_STATUS = const (0x3029 )
437
+
438
+
417
439
_sensor_default_regs = [
418
440
_SYSTEM_CTROL0 , 0x82 , # software reset
419
441
_REG_DLY , 10 , # delay 10ms
@@ -936,6 +958,27 @@ def __set__(self, obj: "OV5640", value: int) -> None:
936
958
937
959
938
960
class _SCCB16CameraBase : # pylint: disable=too-few-public-methods
961
+ _finalize_firmware_load = (
962
+ 0x3022 ,
963
+ 0x00 ,
964
+ 0x3023 ,
965
+ 0x00 ,
966
+ 0x3024 ,
967
+ 0x00 ,
968
+ 0x3025 ,
969
+ 0x00 ,
970
+ 0x3026 ,
971
+ 0x00 ,
972
+ 0x3027 ,
973
+ 0x00 ,
974
+ 0x3028 ,
975
+ 0x00 ,
976
+ 0x3029 ,
977
+ 0x7F ,
978
+ 0x3000 ,
979
+ 0x00 ,
980
+ )
981
+
939
982
def __init__ (self , i2c_bus : I2C , i2c_address : int ) -> None :
940
983
self ._i2c_device = I2CDevice (i2c_bus , i2c_address )
941
984
self ._bank = None
@@ -1004,6 +1047,7 @@ def __init__(
1004
1047
mclk_frequency : int = 20_000_000 ,
1005
1048
i2c_address : int = 0x3C ,
1006
1049
size : int = OV5640_SIZE_QQVGA ,
1050
+ init_autofocus : bool = True ,
1007
1051
): # pylint: disable=too-many-arguments
1008
1052
"""
1009
1053
Args:
@@ -1028,6 +1072,7 @@ def __init__(
1028
1072
with sufficiently low jitter.
1029
1073
i2c_address (int): The I2C address of the camera.
1030
1074
size (int): The captured image size
1075
+ init_autofocus (bool): initialize autofocus
1031
1076
"""
1032
1077
1033
1078
# Initialize the master clock
@@ -1078,8 +1123,100 @@ def __init__(
1078
1123
self ._white_balance = 0
1079
1124
self .size = size
1080
1125
1126
+ if init_autofocus :
1127
+ self .autofocus_init ()
1128
+
1081
1129
chip_id = _RegBits16 (_CHIP_ID_HIGH , 0 , 0xFFFF )
1082
1130
1131
+ def autofocus_init_from_file (self , filename ):
1132
+ """Initialize the autofocus engine from a .bin file"""
1133
+ with open (filename , mode = "rb" ) as file :
1134
+ firmware = file .read ()
1135
+ self .autofocus_init_from_bitstream (firmware )
1136
+
1137
+ def autofocus_init_from_bitstream (self , firmware : bytes ):
1138
+ """Initialize the autofocus engine from a bytestring"""
1139
+ self ._write_register (0x3000 , 0x20 ) # reset autofocus coprocessor
1140
+ time .sleep (0.01 )
1141
+
1142
+ arr = bytearray (256 )
1143
+ with self ._i2c_device as i2c :
1144
+ for offset in range (0 , len (firmware ), 254 ):
1145
+ num_firmware_bytes = min (254 , len (firmware ) - offset )
1146
+ reg = offset + 0x8000
1147
+ arr [0 ] = reg >> 8
1148
+ arr [1 ] = reg & 0xFF
1149
+ arr [2 : 2 + num_firmware_bytes ] = firmware [
1150
+ offset : offset + num_firmware_bytes
1151
+ ]
1152
+ i2c .write (arr , end = 2 + num_firmware_bytes )
1153
+
1154
+ self ._write_list (self ._finalize_firmware_load )
1155
+ for _ in range (100 ):
1156
+ if self .autofocus_status == _OV5640_STAT_IDLE :
1157
+ break
1158
+ time .sleep (0.01 )
1159
+ else :
1160
+ raise RuntimeError ("Timed out after trying to load autofocus firmware" )
1161
+
1162
+ def autofocus_init (self ):
1163
+ """Initialize the autofocus engine from ov5640_autofocus.bin"""
1164
+ if "/" in __file__ :
1165
+ binfile = (
1166
+ __file__ .rsplit ("/" , 1 )[0 ].rsplit ("." , 1 )[0 ] + "/ov5640_autofocus.bin"
1167
+ )
1168
+ else :
1169
+ binfile = "ov5640_autofocus.bin"
1170
+ print (binfile )
1171
+ return self .autofocus_init_from_file (binfile )
1172
+
1173
+ @property
1174
+ def autofocus_status (self ):
1175
+ """Read the camera autofocus status register"""
1176
+ return self ._read_register (_OV5640_CMD_FW_STATUS )
1177
+
1178
+ def _send_autofocus_command (self , command , msg ): # pylint: disable=unused-argument
1179
+ self ._write_register (_OV5640_CMD_ACK , 0x01 ) # clear command ack
1180
+ self ._write_register (_OV5640_CMD_MAIN , command ) # send command
1181
+ for _ in range (1000 ):
1182
+ if self ._read_register (_OV5640_CMD_ACK ) == 0x0 : # command is finished
1183
+ return True
1184
+ time .sleep (0.01 )
1185
+ return False
1186
+
1187
+ def autofocus (self ) -> list [int ]:
1188
+ """Perform an autofocus operation.
1189
+
1190
+ If all elements of the list are 0, the autofocus operation failed. Otherwise,
1191
+ if at least one element is nonzero, the operation succeeded.
1192
+
1193
+ In principle the elements correspond to 5 autofocus regions, if configured."""
1194
+ if not self ._send_autofocus_command (_OV5640_CMD_RELEASE_FOCUS , "release focus" ):
1195
+ return [False ] * 5
1196
+ if not self ._send_autofocus_command (_OV5640_CMD_TRIGGER_AUTOFOCUS , "autofocus" ):
1197
+ return [False ] * 5
1198
+ zone_focus = [self ._read_register (_OV5640_CMD_PARA0 + i ) for i in range (5 )]
1199
+ print (f"zones focused: { zone_focus } " )
1200
+ return zone_focus
1201
+
1202
+ @property
1203
+ def autofocus_vcm_step (self ):
1204
+ """Get the voice coil motor step location"""
1205
+ if not self ._send_autofocus_command (
1206
+ _OV5640_CMD_AF_GET_VCM_STEP , "get vcm step"
1207
+ ):
1208
+ return None
1209
+ return self ._read_register (_OV5640_CMD_PARA4 )
1210
+
1211
+ @autofocus_vcm_step .setter
1212
+ def autofocus_vcm_step (self , step ):
1213
+ """Get the voice coil motor step location, from 0 to 255"""
1214
+ if not 0 <= step <= 255 :
1215
+ raise RuntimeError ("VCM step must be 0 to 255" )
1216
+ self ._write_register (_OV5640_CMD_PARA3 , 0x00 )
1217
+ self ._write_register (_OV5640_CMD_PARA4 , step )
1218
+ self ._send_autofocus_command (_OV5640_CMD_AF_SET_VCM_STEP , "set vcm step" )
1219
+
1083
1220
def capture (self , buf : Union [bytearray , memoryview ]) -> None :
1084
1221
"""Capture an image into the buffer.
1085
1222
0 commit comments