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

     1  // Package qmi8658c provides a driver for the QMI8658C accelerometer and gyroscope
     2  // made by QST Solutions.
     3  //
     4  // Datasheet:
     5  // https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf
     6  package qmi8656c
     7  
     8  import (
     9  	"tinygo.org/x/drivers"
    10  	"tinygo.org/x/drivers/internal/legacy"
    11  )
    12  
    13  // Device wraps the I2C connection to the QMIC8658 sensor
    14  type Device struct {
    15  	bus        drivers.I2C
    16  	Address    uint16
    17  	AccLsbDiv  uint16
    18  	GyroLsbDiv uint16
    19  }
    20  
    21  type Config struct {
    22  	// SPI Config
    23  	SPIMode    byte // One of SPI_X_WIRE
    24  	SPIEndian  byte // One of SPI_XXX_ENDIAN
    25  	SPIAutoInc byte // One of SPI_NOT_AUTO_INC or SPI_AUTO_INC
    26  	// Accelerometer
    27  	AccEnable  byte // One of ACC_ENABLE or ACC_DISABLE
    28  	AccScale   byte // One of ACC_XG
    29  	AccRate    byte // One of ACC_XX_YYHZ
    30  	AccLowPass byte // One of ACC_LOW_PASS_X
    31  	// Gyro
    32  	GyroEnable  byte // One of GYRO_X_ENABLE or GYRO_DISABLE
    33  	GyroScale   byte // One of GYRO_XDPS
    34  	GyroRate    byte // One of GYRO_X_YHZ
    35  	GyroLowPass byte // One of GYRO_LOW_PASS_X
    36  }
    37  
    38  // Create a new device with the I2C passed, correct address and nil values for
    39  // AccLsbDiv and GyroLsbDiv, which will be corrected based on the config.
    40  func New(bus drivers.I2C) Device {
    41  	return Device{
    42  		bus,
    43  		Address,
    44  		1,
    45  		1,
    46  	}
    47  }
    48  
    49  // Check if the device is connected by calling WHO_AM_I and checking the
    50  // default identifier.
    51  func (d *Device) Connected() bool {
    52  	data := []byte{0}
    53  	d.ReadRegister(WHO_AM_I, data)
    54  	return data[0] == IDENTIFIER
    55  }
    56  
    57  // Create a basic default configuration that works with the "WaveShare RP2040
    58  // Round LCD 1.28in".
    59  func DefaultConfig() (cfg Config) {
    60  	return Config{
    61  		SPIMode:     SPI_4_WIRE,
    62  		SPIEndian:   SPI_BIG_ENDIAN,
    63  		SPIAutoInc:  SPI_AUTO_INC,
    64  		AccEnable:   ACC_ENABLE,
    65  		AccScale:    ACC_8G,
    66  		AccRate:     ACC_NORMAL_1000HZ,
    67  		AccLowPass:  ACC_LOW_PASS_2_62,
    68  		GyroEnable:  GYRO_FULL_ENABLE,
    69  		GyroScale:   GYRO_512DPS,
    70  		GyroRate:    GYRO_1000HZ,
    71  		GyroLowPass: GYRO_LOW_PASS_2_62,
    72  	}
    73  }
    74  
    75  // Check if the user has defined a desired configuration, if not uses the
    76  // DefaultConfig, then defines the AccLsbDiv and GyroLsbDiv based on the
    77  // configurations and, finally, send the commands and configure the IMU.
    78  func (d *Device) Configure(cfg Config) {
    79  	if cfg == (Config{}) {
    80  		cfg = DefaultConfig()
    81  	}
    82  	var val uint16
    83  	// Setting accelerometer LSB
    84  	switch cfg.AccScale {
    85  	case ACC_2G:
    86  		d.AccLsbDiv = 1 << 14
    87  	case ACC_4G:
    88  		d.AccLsbDiv = 1 << 13
    89  	case ACC_8G:
    90  		d.AccLsbDiv = 1 << 12
    91  	case ACC_16G:
    92  		d.AccLsbDiv = 1 << 11
    93  	default:
    94  		d.AccLsbDiv = 1 << 12
    95  	}
    96  	// Setting gyro LSB
    97  	switch cfg.GyroScale {
    98  	case GYRO_16DPS:
    99  		d.GyroLsbDiv = 2048
   100  	case GYRO_32DPS:
   101  		d.GyroLsbDiv = 1024
   102  	case GYRO_64DPS:
   103  		d.GyroLsbDiv = 512
   104  	case GYRO_128DPS:
   105  		d.GyroLsbDiv = 256
   106  	case GYRO_256DPS:
   107  		d.GyroLsbDiv = 128
   108  	case GYRO_512DPS:
   109  		d.GyroLsbDiv = 64
   110  	case GYRO_1024DPS:
   111  		d.GyroLsbDiv = 32
   112  	case GYRO_2048DPS:
   113  		d.GyroLsbDiv = 16
   114  	default:
   115  		d.GyroLsbDiv = 64
   116  	}
   117  	// SPI Modes
   118  	val = uint16((cfg.SPIMode | cfg.SPIEndian | cfg.SPIAutoInc))
   119  	d.WriteRegister(CTRL1, val)
   120  	// Accelerometer config
   121  	val = uint16(cfg.AccScale | cfg.AccRate)
   122  	d.WriteRegister(CTRL2, val)
   123  	// Gyro config
   124  	val = uint16(cfg.GyroScale | cfg.GyroRate)
   125  	d.WriteRegister(CTRL3, val)
   126  	// Sensor DSP config
   127  	val = uint16(cfg.GyroLowPass | cfg.AccLowPass)
   128  	d.WriteRegister(CTRL5, val)
   129  	// Sensors config
   130  	val = uint16(cfg.GyroEnable | cfg.AccEnable)
   131  	d.WriteRegister(CTRL7, val)
   132  }
   133  
   134  // Read the acceleration from the sensor, the values returned are in mg
   135  // (milli gravity), which means that 1000 = 1g.
   136  func (d *Device) ReadAcceleration() (x int32, y int32, z int32) {
   137  	data := make([]byte, 6)
   138  	raw := make([]int32, 3)
   139  	d.ReadRegister(ACC_XOUT_L, data)
   140  	for i := range raw {
   141  		raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
   142  		if raw[i] >= 32767 {
   143  			raw[i] = raw[i] - 65535
   144  		}
   145  	}
   146  	x = -raw[0] * 1000 / int32(d.AccLsbDiv)
   147  	y = -raw[1] * 1000 / int32(d.AccLsbDiv)
   148  	z = -raw[2] * 1000 / int32(d.AccLsbDiv)
   149  	return x, y, z
   150  }
   151  
   152  // Read the rotation from the sensor, the values returned are in mdeg/sec
   153  // (milli degress/second), which means that a full rotation is 360000.
   154  func (d *Device) ReadRotation() (x int32, y int32, z int32) {
   155  	data := make([]byte, 6)
   156  	raw := make([]int32, 3)
   157  	d.ReadRegister(GYRO_XOUT_L, data)
   158  	for i := range raw {
   159  		raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
   160  		if raw[i] >= 32767 {
   161  			raw[i] = raw[i] - 65535
   162  		}
   163  	}
   164  	x = raw[0] * 1000 / int32(d.GyroLsbDiv)
   165  	y = raw[1] * 1000 / int32(d.GyroLsbDiv)
   166  	z = raw[2] * 1000 / int32(d.GyroLsbDiv)
   167  	return x, y, z
   168  }
   169  
   170  // Read the temperature from the sensor, the values returned are in
   171  // millidegrees Celsius.
   172  func (d *Device) ReadTemperature() (int32, error) {
   173  	data := make([]byte, 2)
   174  	err := d.ReadRegister(TEMP_OUT_L, data)
   175  	if err != nil {
   176  		return 0, err
   177  	}
   178  	raw := uint16(data[1])<<8 | uint16(data[0])
   179  	t := int32(raw) * 1000 / 256
   180  	return t, err
   181  }
   182  
   183  // Convenience method to read the register and avoid repetition.
   184  func (d *Device) ReadRegister(reg uint8, buf []byte) error {
   185  	return legacy.ReadRegister(d.bus, uint8(d.Address), reg, buf)
   186  }
   187  
   188  // Convenience method to write the register and avoid repetition.
   189  func (d *Device) WriteRegister(reg uint8, v uint16) error {
   190  	data := []byte{byte(v)}
   191  	err := legacy.WriteRegister(d.bus, uint8(d.Address), reg, data)
   192  	return err
   193  }