tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/vl6180x/vl6180x.go (about)

     1  // Package vl6180x provides a driver for the VL6180X time-of-flight distance sensor
     2  //
     3  // Datasheet:
     4  // https://www.st.com/resource/en/datasheet/vl6180x.pdf
     5  // This driver was based on the library https://github.com/adafruit/Adafruit_VL6180X
     6  // and document 'AN4545 VL6180X basic ranging application note':
     7  // https://www.st.com/resource/en/application_note/an4545-vl6180x-basic-ranging-application-note-stmicroelectronics.pdf
     8  package vl6180x // import "tinygo.org/x/drivers/vl6180x"
     9  
    10  import (
    11  	"time"
    12  
    13  	"tinygo.org/x/drivers"
    14  )
    15  
    16  type VL6180XError uint8
    17  
    18  // Device wraps an I2C connection to a VL6180X device.
    19  type Device struct {
    20  	bus     drivers.I2C
    21  	Address uint16
    22  	timeout uint32
    23  }
    24  
    25  // New creates a new VL6180X connection. The I2C bus must already be
    26  // configured.
    27  //
    28  // This function only creates the Device object, it does not touch the device.
    29  func New(bus drivers.I2C) Device {
    30  	return Device{
    31  		bus:     bus,
    32  		Address: Address,
    33  		timeout: 500,
    34  	}
    35  }
    36  
    37  // Connected returns whether a VL6180X has been found.
    38  // It does a "who am I" request and checks the response.
    39  func (d *Device) Connected() bool {
    40  	return d.readReg(WHO_AM_I) == CHIP_ID
    41  }
    42  
    43  // Configure sets up the device for communication
    44  func (d *Device) Configure(use2v8Mode bool) bool {
    45  	if !d.Connected() {
    46  		return false
    47  	}
    48  
    49  	if (d.readReg(SYSTEM_FRESH_OUT_OF_RESET) & 0x01) == 0x01 {
    50  
    51  		// mandatory settings from page 24 of AN4545
    52  		d.writeReg(0x0207, 0x01)
    53  		d.writeReg(0x0208, 0x01)
    54  		d.writeReg(0x0096, 0x00)
    55  		d.writeReg(0x0097, 0xfd)
    56  		d.writeReg(0x00e3, 0x00)
    57  		d.writeReg(0x00e4, 0x04)
    58  		d.writeReg(0x00e5, 0x02)
    59  		d.writeReg(0x00e6, 0x01)
    60  		d.writeReg(0x00e7, 0x03)
    61  		d.writeReg(0x00f5, 0x02)
    62  		d.writeReg(0x00d9, 0x05)
    63  		d.writeReg(0x00db, 0xce)
    64  		d.writeReg(0x00dc, 0x03)
    65  		d.writeReg(0x00dd, 0xf8)
    66  		d.writeReg(0x009f, 0x00)
    67  		d.writeReg(0x00a3, 0x3c)
    68  		d.writeReg(0x00b7, 0x00)
    69  		d.writeReg(0x00bb, 0x3c)
    70  		d.writeReg(0x00b2, 0x09)
    71  		d.writeReg(0x00ca, 0x09)
    72  		d.writeReg(0x0198, 0x01)
    73  		d.writeReg(0x01b0, 0x17)
    74  		d.writeReg(0x01ad, 0x00)
    75  		d.writeReg(0x00ff, 0x05)
    76  		d.writeReg(0x0100, 0x05)
    77  		d.writeReg(0x0199, 0x05)
    78  		d.writeReg(0x01a6, 0x1b)
    79  		d.writeReg(0x01ac, 0x3e)
    80  		d.writeReg(0x01a7, 0x1f)
    81  		d.writeReg(0x0030, 0x00)
    82  
    83  		// recommended settings
    84  		d.writeReg(0x0011, 0x10) // enables polling when measurement completes
    85  		d.writeReg(0x010a, 0x30) // sets averaging sample period
    86  		d.writeReg(0x003f, 0x46) // sets light and dark gain
    87  		d.writeReg(0x0031, 0xFF) // sets the # of range measurements for auto calibration
    88  		d.writeReg(0x0041, 0x63) // sets ALS integration time to 100ms
    89  		d.writeReg(0x002e, 0x01) // performs a single temperature calibration
    90  
    91  		// optional settings
    92  		d.writeReg(RANGING_INTERMEASUREMENT_PERIOD, 0x09) // sets ranging inter-measurement period to 100ms
    93  		d.writeReg(ALS_INTERMEASUREMENT_PERIOD, 0x31)     // sets default ALS inter-measurement period to 500ms
    94  		d.writeReg(SYSTEM_INTERRUPT_CONFIG, 0x24)         // configures interrupt
    95  
    96  		d.writeReg(SYSTEM_FRESH_OUT_OF_RESET, 0x00)
    97  		time.Sleep(100 * time.Microsecond)
    98  	}
    99  
   100  	return true
   101  }
   102  
   103  // Read returns the proximity of the sensor in mm
   104  func (d *Device) Read() uint16 {
   105  	start := time.Now()
   106  
   107  	for d.dataReady() {
   108  		elapsed := time.Since(start)
   109  		if d.timeout > 0 && uint32(elapsed.Seconds()*1000) > d.timeout {
   110  			return 0
   111  		}
   112  	}
   113  
   114  	d.writeReg(SYSRANGE_START, 0x01)
   115  	for (d.readReg(RESULT_INTERRUPT_STATUS_GPIO) & 0x04) == 0 {
   116  	}
   117  
   118  	return uint16(d.readRangeResult())
   119  }
   120  
   121  // dataReady returns true when the data is ready to be read
   122  func (d *Device) dataReady() bool {
   123  	return (d.readReg(RESULT_RANGE_STATUS) & 0x01) == 0
   124  }
   125  
   126  // startRange starts the readings
   127  func (d *Device) startRange() {
   128  	for d.dataReady() {
   129  	}
   130  	d.writeReg(SYSRANGE_START, 0x01)
   131  }
   132  
   133  // IsRangeComplete return true when the reading is complete
   134  func (d *Device) IsRangeComplete() bool {
   135  	if (d.readReg(RESULT_INTERRUPT_STATUS_GPIO) & 0x04) != 0 {
   136  		return true
   137  	}
   138  	return false
   139  }
   140  
   141  // readRangeResults returns the sensor value from the register
   142  func (d *Device) readRangeResult() uint8 {
   143  	value := d.readReg(RESULT_RANGE_VAL)
   144  
   145  	d.writeReg(SYSTEM_INTERRUPT_CLEAR, 0x07)
   146  	return value
   147  }
   148  
   149  // StartRangeContinuous starts the continuous reading mode
   150  func (d *Device) StartRangeContinuous(periodInMs uint16) {
   151  	var periodReg uint8
   152  	if periodInMs > 10 {
   153  		if periodInMs < 2550 {
   154  			periodReg = uint8(periodInMs/10) - 1
   155  		} else {
   156  			periodReg = 254
   157  		}
   158  	}
   159  	d.writeReg(RANGING_INTERMEASUREMENT_PERIOD, periodReg)
   160  	d.writeReg(SYSRANGE_START, 0x03)
   161  }
   162  
   163  // StopRangeContinuous stops the continuous reading mode
   164  func (d *Device) StopRangeContinuous() {
   165  	d.writeReg(SYSRANGE_START, 0x01)
   166  }
   167  
   168  // ReadStatus returns the current status of the sensor
   169  func (d *Device) ReadStatus() uint8 {
   170  	return d.readReg(RESULT_RANGE_STATUS) >> 4
   171  }
   172  
   173  // ReadLux returns the lux of the sensor
   174  func (d *Device) ReadLux(gain uint8) (lux uint32) {
   175  	reg := d.readReg(SYSTEM_INTERRUPT_CONFIG)
   176  	reg &= ^uint8(0x38)
   177  	reg |= 0x4 << 3
   178  	d.writeReg(SYSTEM_INTERRUPT_CONFIG, reg)
   179  
   180  	d.writeReg(SYSALS_INTEGRATION_PERIOD_HI, 0)
   181  	d.writeReg(SYSALS_INTEGRATION_PERIOD_HI, 100)
   182  
   183  	if gain > ALS_GAIN_40 {
   184  		gain = ALS_GAIN_40
   185  	}
   186  	d.writeReg(SYSALS_ANALOGUE_GAIN, 0x40|gain)
   187  
   188  	d.writeReg(SYSALS_START, 0x1)
   189  	for 4 != ((d.readReg(RESULT_INTERRUPT_STATUS_GPIO) >> 3) & 0x7) {
   190  	}
   191  
   192  	lux = uint32(d.readReg16Bit(RESULT_ALS_VAL)) * 320
   193  	d.writeReg(SYSTEM_INTERRUPT_CLEAR, 0x07)
   194  
   195  	switch gain {
   196  	case ALS_GAIN_1:
   197  		break
   198  	case ALS_GAIN_1_25:
   199  		lux = (lux * 100) / 125
   200  		break
   201  	case ALS_GAIN_1_67:
   202  		lux = (lux * 100) / 167
   203  		break
   204  	case ALS_GAIN_2_5:
   205  		lux = (lux * 10) / 25
   206  		break
   207  	case ALS_GAIN_5:
   208  		lux /= 5
   209  		break
   210  	case ALS_GAIN_10:
   211  		lux /= 10
   212  		break
   213  	case ALS_GAIN_20:
   214  		lux /= 20
   215  		break
   216  	case ALS_GAIN_40:
   217  		lux /= 40
   218  		break
   219  	}
   220  
   221  	return lux
   222  }
   223  
   224  // SetOffset sets the offset
   225  func (d *Device) SetOffset(offset uint8) {
   226  	d.writeReg(SYSRANGE_PART_TO_PART_RANGE_OFFSET, offset)
   227  }
   228  
   229  // SetAddress sets the I2C address which this device listens to.
   230  func (d *Device) SetAddress(address uint8) {
   231  	d.writeReg(I2C_SLAVE_DEVICE_ADDRESS, address)
   232  	d.Address = uint16(address)
   233  }
   234  
   235  // GetAddress returns the I2C address which this device listens to.
   236  func (d *Device) GetAddress() uint8 {
   237  	return uint8(d.Address)
   238  }
   239  
   240  // writeReg sends a single byte to the specified register address
   241  func (d *Device) writeReg(reg uint16, value uint8) {
   242  	msb := byte((reg >> 8) & 0xFF)
   243  	lsb := byte(reg & 0xFF)
   244  	d.bus.Tx(d.Address, []byte{msb, lsb, value}, nil)
   245  }
   246  
   247  // readReg reads a single byte from the specified address
   248  func (d *Device) readReg(reg uint16) uint8 {
   249  	data := []byte{0}
   250  	msb := byte((reg >> 8) & 0xFF)
   251  	lsb := byte(reg & 0xFF)
   252  	d.bus.Tx(d.Address, []byte{msb, lsb}, data)
   253  	return data[0]
   254  }
   255  
   256  // readReg16Bit reads two bytes from the specified address
   257  // and returns it as a uint16
   258  func (d *Device) readReg16Bit(reg uint16) uint16 {
   259  	data := []byte{0, 0}
   260  	msb := byte((reg >> 8) & 0xFF)
   261  	lsb := byte(reg & 0xFF)
   262  	d.bus.Tx(d.Address, []byte{msb, lsb}, data)
   263  	return readUint(data[0], data[1])
   264  }
   265  
   266  // readUint converts two bytes to uint16
   267  func readUint(msb byte, lsb byte) uint16 {
   268  	return (uint16(msb) << 8) | uint16(lsb)
   269  }