Source code for pyripherals.peripherals.TMF8801

from ..core import Register
from ..utils import int_to_list
from .I2CController import I2CController
import time


[docs]class TMF8801(I2CController): """Class for the Time-of-flight I2C device Subclass of the I2CController class. Attributes and methods below are differences in this class from I2CController only. Attributes ---------- ADDRESS : int 7-bit device address with R/W bit space registers : dict Name-Register pairs for the internal registers of the chip. """ ADDRESS = 0b0100_0001 << 1 registers = Register.get_chip_registers('TMF8801') apps = {'measure': 0xC0, 'bootloader': 0x80} MULTI_BYTE_ORDER = 'LSB_1st'
[docs] def write(self, data, register_name): """Write data to any register on the chip. first reads to enable writing of (just) bit-fields within the register """ dev_addr = self.ADDRESS register = self.registers[register_name] data <<= register.bit_index_low # Mask only the bits for the specified register. mask = 0 for bit in range(register.bit_index_high, register.bit_index_low - 1, -1): mask |= 0x1 << bit # Compare with current data to mask unchanged values read_out = self.read(register_name) if read_out == None: print('Read for masking FAILED') return False new_data = (data & mask) | (read_out & ~mask) # Turn data into a list of bytes for i2c_write method list_data = int_to_list(new_data) number_of_bytes = len(list_data) list_data_str = ''.join(" ".join(f'0x{x:02x}' for x in list_data)) print( f'i2c write long: 0x{dev_addr:02x}, reg addr 0x{register.address:02x}, data {list_data_str}') self.i2c_write_long( dev_addr, [register.address], number_of_bytes, list_data)
[docs] def read(self, register_name, number_of_bytes=None): """Return data from any register on the chip.""" dev_addr = self.ADDRESS register = self.registers[register_name] # This is the total number of bytes to read byte_number = (register.bit_index_high // 8) + 1 # e.g. 16-bit register = 2 bytes, i2c_read_long starts at the MSB so we read 2 bytes to get Byte 0 if number_of_bytes is None: number_of_bytes = byte_number # print(f'Read slave address: 0x{dev_addr:02x}, reg addr 0x{register.address:02x}') read_back_list = self.i2c_read_long( dev_addr, [register.address], number_of_bytes) # Turn the list into an integer read_back_data = 0 if read_back_list == None: return None if self.MULTI_BYTE_ORDER == 'MSB_1st': for byte in read_back_list: # print('Readback byte of 0x{:02X}'.format(byte)) read_back_data <<= 8 read_back_data |= byte elif self.MULTI_BYTE_ORDER == 'LSB_1st': for byte in read_back_list[::-1]: # flip list order # print('Readback byte of 0x{:02X}'.format(byte)) read_back_data <<= 8 read_back_data |= byte # Get only the bits for the specified register from what was read back. desired_bits = 0 for bit in range(register.bit_index_high, register.bit_index_low - 1, -1): desired_bits += 0x1 << bit desired_data = (read_back_data & desired_bits) >> register.bit_index_low return desired_data
[docs] def power_down_high_impedance(self): """Power down the DAC output to high impedance (default).""" pass
# self.write(0b10, 'DAC_PDN')
[docs] def get_id(self): """Return the device ID and rev ID as one integer.""" device_id = self.read('ID') version_id = self.read('REVID') return (device_id << self.registers['ID'].bit_index_low) | (version_id << self.registers['ID'].bit_index_low)
def cpu_reset(self): self.write(1, 'CPU_RESET') def cpu_ready(self): return self.read('CPU_READY', 1) def load_app(self, app='measure'): if app == 'measure': val = 0xC0 elif app == 'bootloader': val = 0x80 self.write(val, 'APPREQID') return self.read('APPID') def read_app(self): appid = self.read('APPID') appname = list(self.apps.keys())[list(self.apps.values()).index(appid)] print(f'In app {appname}') return appid def rom_fw_version(self): rev_major = self.read('APPREV_MAJOR', number_of_bytes=1) rev_minor = self.read('APPREV_MINOR', number_of_bytes=1) patch = self.read('APPREV_PATCH', number_of_bytes=1) print(f'major: {rev_major}, minor: {rev_minor}, patch: {patch}') return rev_major, rev_minor, patch def bl_command(self, cmd): appid = self.read('APPID') if appid == self.apps['bootloader']: print('cannot send boatloader command when in measure app') return 0 if cmd == 'ramremap_reset': val = 0x11 elif cmd == 'download_init': val = 0x14 self.write(val, 'CMD_DATA7') def ram_write_status(self): # TODO: Host_Driver_Comm document suggests this reads back 3 bytes return self.read('CMD_DATA7', number_of_bytes=3) def download_init(self): dev_addr = self.ADDRESS reg_addr = self.registers['CMD_DATA7'].address # TODO: why 0x29 - specified by host driver comms data = [0x14, 0x01, 0x29, 0xC1] self.i2c_write_long(dev_addr, [reg_addr], len(data), data) def ramremap_reset(self): dev_addr = self.ADDRESS reg_addr = self.registers['CMD_DATA7'].address data = [0x11, 0x00, 0xEE] self.i2c_write_long(dev_addr, [reg_addr], len(data), data) def read_dist_peak(self): dev_addr = self.ADDRESS reg_addr = self.registers['DISTANCE_PEAK'].address num_bytes = self.registers['DISTANCE_PEAK'].bit_width//8 return self.i2c_read_long(dev_addr, [reg_addr], data_length=num_bytes)
[docs] def read_data(self): """ For correctly updating of these registers by TMF8801, an I2C block read starting from address 0x1D until 0x27 shall be done. 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27""" dev_addr = self.ADDRESS reg_addr = self.registers['STATUS'].address read_data = self.i2c_read_long(dev_addr, [reg_addr], data_length=11) vals = {'status': read_data[0], 'register_contents': read_data[1], 'transaction_id': read_data[2], 'result_num': read_data[3], 'result_info': read_data[4], 'dist_mm': read_data[5] + (read_data[6] << 8), 'sys_clk': read_data[7] + (read_data[8] << 8) + (read_data[9] << 16) + (read_data[10] << 24)} vals['sys_clk_seconds'] = vals['sys_clk']*0.2e-6 return vals, read_data
def read_by_addr(self, reg_addr, num_bytes=1): dev_addr = self.ADDRESS return self.i2c_read_long(dev_addr, [reg_addr], data_length=num_bytes)
[docs] def factory_calibration(self, filename=None): """ Perform factory calibration and return 14 bytes of data See AN000597 -- Factor Calibration 8.1 Calibration Environment: Device has to be in the final (correct) optical stack Clear glass (no smudge on the glass) No target in front of the device within 40 cm (see datasheet) Dark room or low ambient light """ print('Factory calibration: device should be in dark room with no objects within 40 cm') self.write(0x0A, 'COMMAND') # Command is register 0x10 time.sleep(2) cal_done = 0 count = 0 while (cal_done != 0x0A) and (count < 20): cal_done = self.read('REGISTER_CONTENTS') time.sleep(0.1) count = count + 1 print(f'Cal done 0x{cal_done:02x}') cal_data = self.read_by_addr(0x20, num_bytes=14) print('Calibration data') for d in cal_data: print(d) with open(filename, 'w') as f: f.write(','.join(cal_data)) return cal_data