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

     1  // Package amg88xx provides a driver for the AMG88XX Thermal Camera
     2  //
     3  // Datasheet:
     4  // https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf
     5  package amg88xx // import "tinygo.org/x/drivers/amg88xx"
     6  
     7  import (
     8  	"time"
     9  
    10  	"tinygo.org/x/drivers"
    11  	"tinygo.org/x/drivers/internal/legacy"
    12  )
    13  
    14  // Device wraps an I2C connection to a AMG88xx device.
    15  type Device struct {
    16  	bus             drivers.I2C
    17  	Address         uint16
    18  	data            []uint8
    19  	interruptMode   InterruptMode
    20  	interruptEnable uint8
    21  }
    22  
    23  type InterruptMode uint8
    24  
    25  type Config struct {
    26  }
    27  
    28  // New creates a new AMG88xx connection. The I2C bus must already be
    29  // configured.
    30  //
    31  // This function only creates the Device object, it does not touch the device.
    32  func New(bus drivers.I2C) Device {
    33  	return Device{
    34  		bus:     bus,
    35  		Address: AddressHigh,
    36  	}
    37  }
    38  
    39  // Configure sets up the device for communication
    40  func (d *Device) Configure(cfg Config) {
    41  	d.data = make([]uint8, 128)
    42  
    43  	d.SetPCTL(NORMAL_MODE)
    44  	d.SetReset(INITIAL_RESET)
    45  	d.SetFrameRate(FPS_10)
    46  
    47  	time.Sleep(100 * time.Millisecond)
    48  }
    49  
    50  // ReadPixels returns the 64 values (8x8 grid) of the sensor converted to  millicelsius
    51  func (d *Device) ReadPixels(buffer *[64]int16) {
    52  	legacy.ReadRegister(d.bus, uint8(d.Address), PIXEL_OFFSET, d.data)
    53  	for i := 0; i < 64; i++ {
    54  		buffer[i] = int16((uint16(d.data[2*i+1]) << 8) | uint16(d.data[2*i]))
    55  		if (buffer[i] & (1 << 11)) > 0 { // temperature negative
    56  			buffer[i] &= ^(1 << 11)
    57  			buffer[i] = -buffer[i]
    58  		}
    59  		buffer[i] *= PIXEL_TEMP_CONVERSION
    60  	}
    61  }
    62  
    63  // SetPCTL sets the PCTL
    64  func (d *Device) SetPCTL(pctl uint8) {
    65  	legacy.WriteRegister(d.bus, uint8(d.Address), PCTL, []byte{pctl})
    66  }
    67  
    68  // SetReset sets the reset value
    69  func (d *Device) SetReset(rst uint8) {
    70  	legacy.WriteRegister(d.bus, uint8(d.Address), RST, []byte{rst})
    71  }
    72  
    73  // SetFrameRate configures the frame rate
    74  func (d *Device) SetFrameRate(framerate uint8) {
    75  	legacy.WriteRegister(d.bus, uint8(d.Address), FPSC, []byte{framerate & 0x01})
    76  }
    77  
    78  // SetMovingAverageMode sets the moving average mode
    79  func (d *Device) SetMovingAverageMode(mode bool) {
    80  	var value uint8
    81  	if mode {
    82  		value = 1
    83  	}
    84  	legacy.WriteRegister(d.bus, uint8(d.Address), AVE, []byte{value << 5})
    85  }
    86  
    87  // SetInterruptLevels sets the interrupt levels
    88  func (d *Device) SetInterruptLevels(high int16, low int16) {
    89  	d.SetInterruptLevelsHysteresis(high, low, (high*95)/100)
    90  }
    91  
    92  // SetInterruptLevelsHysteresis sets the interrupt levels with hysteresis
    93  func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis int16) {
    94  	high = high / PIXEL_TEMP_CONVERSION
    95  	if high < -4095 {
    96  		high = -4095
    97  	}
    98  	if high > 4095 {
    99  		high = 4095
   100  	}
   101  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
   102  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
   103  
   104  	low = low / PIXEL_TEMP_CONVERSION
   105  	if low < -4095 {
   106  		low = -4095
   107  	}
   108  	if low > 4095 {
   109  		low = 4095
   110  	}
   111  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
   112  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
   113  
   114  	hysteresis = hysteresis / PIXEL_TEMP_CONVERSION
   115  	if hysteresis < -4095 {
   116  		hysteresis = -4095
   117  	}
   118  	if hysteresis > 4095 {
   119  		hysteresis = 4095
   120  	}
   121  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
   122  	legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
   123  }
   124  
   125  // EnableInterrupt enables the interrupt pin on the device
   126  func (d *Device) EnableInterrupt() {
   127  	d.interruptEnable = 1
   128  	legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
   129  }
   130  
   131  // DisableInterrupt disables the interrupt pin on the device
   132  func (d *Device) DisableInterrupt() {
   133  	d.interruptEnable = 0
   134  	legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
   135  }
   136  
   137  // SetInterruptMode sets the interrupt mode
   138  func (d *Device) SetInterruptMode(mode InterruptMode) {
   139  	d.interruptMode = mode
   140  	legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
   141  }
   142  
   143  // GetInterrupt reads the state of the triggered interrupts
   144  func (d *Device) GetInterrupt() []uint8 {
   145  	data := make([]uint8, 8)
   146  	legacy.ReadRegister(d.bus, uint8(d.Address), INT_OFFSET, data)
   147  	return data
   148  }
   149  
   150  // ClearInterrupt clears any triggered interrupts
   151  func (d *Device) ClearInterrupt() {
   152  	d.SetReset(FLAG_RESET)
   153  }
   154  
   155  // ReadThermistor reads the onboard thermistor
   156  func (d *Device) ReadThermistor() int16 {
   157  	data := make([]uint8, 2)
   158  	legacy.ReadRegister(d.bus, uint8(d.Address), TTHL, data)
   159  	return (int16((uint16(data[1])<<8)|uint16(data[0])) * THERMISTOR_CONVERSION) / 10
   160  }