mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
qmi8658c: Add support for the QMI8658C sensor (#467)
* Add support for the QMI8658C sensor * qmi8656c: update ReadTemperature signature * Update README devices count
This commit is contained in:
@@ -209,6 +209,8 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/qmi8658c/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 83 devices are supported.
|
||||
The following 90 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
|
||||
@@ -112,6 +112,7 @@ The following 83 devices are supported.
|
||||
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
|
||||
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
||||
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
|
||||
| [QMI8658C accelerometer/gyroscope](https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf) | I2C |
|
||||
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
|
||||
| [RTL8720DN 2.4G/5G Dual Bands Wireless and BLE5.0](https://www.seeedstudio.com/Realtek8720DN-2-4G-5G-Dual-Bands-Wireless-and-BLE5-0-Combo-Module-p-4442.html) | UART |
|
||||
| [SCD4x CO2 Sensor](https://sensirion.com/media/documents/C4B87CE6/627C2DCD/CD_DS_SCD40_SCD41_Datasheet_D1.pdf) | I2C |
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Connects to an QMI8658C I2C accelerometer/gyroscope and print the read data.
|
||||
// This example was made with the "WaveShare RP2040 Round LCD 1.28in" in mind.
|
||||
// For more infor about this development board:
|
||||
// https://www.waveshare.com/wiki/RP2040-LCD-1.28
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
imu "tinygo.org/x/drivers/qmi8658c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := machine.I2C1
|
||||
// This is the default pinout for the "WaveShare RP2040 Round LCD 1.28in"
|
||||
err := i2c.Configure(machine.I2CConfig{
|
||||
SDA: machine.GP6,
|
||||
SCL: machine.GP7,
|
||||
Frequency: 100000,
|
||||
})
|
||||
if err != nil {
|
||||
println("unable to configure I2C:", err)
|
||||
return
|
||||
}
|
||||
// Create a new device
|
||||
d := imu.New(i2c)
|
||||
|
||||
// Check if the device is connected
|
||||
if !d.Connected() {
|
||||
println("unable to connect to sensor")
|
||||
return
|
||||
}
|
||||
|
||||
// This IMU has multiple configurations like output data rate, multiple
|
||||
// measurements scales, low pass filters, low power modes, all the vailable
|
||||
// values can be found in the datasheet and were defined at registers file.
|
||||
// This is the default configuration which will be used if the `nil` value
|
||||
// is passed do the `Configure` method.
|
||||
config := imu.Config{
|
||||
SPIMode: imu.SPI_4_WIRE,
|
||||
SPIEndian: imu.SPI_BIG_ENDIAN,
|
||||
SPIAutoInc: imu.SPI_AUTO_INC,
|
||||
AccEnable: imu.ACC_ENABLE,
|
||||
AccScale: imu.ACC_8G,
|
||||
AccRate: imu.ACC_NORMAL_1000HZ,
|
||||
AccLowPass: imu.ACC_LOW_PASS_2_62,
|
||||
GyroEnable: imu.GYRO_FULL_ENABLE,
|
||||
GyroScale: imu.GYRO_512DPS,
|
||||
GyroRate: imu.GYRO_1000HZ,
|
||||
GyroLowPass: imu.GYRO_LOW_PASS_2_62,
|
||||
}
|
||||
d.Configure(config)
|
||||
|
||||
// Read the accelation, rotation and temperature data and print them.
|
||||
for {
|
||||
acc_x, acc_y, acc_z := d.ReadAcceleration()
|
||||
gyro_x, gyro_y, gyro_z := d.ReadRotation()
|
||||
temp, _ := d.ReadTemperature()
|
||||
println("-------------------------------")
|
||||
println("acc:", acc_x, acc_y, acc_z)
|
||||
println("gyro:", gyro_x, gyro_y, gyro_z)
|
||||
println("temp:", temp)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// Package qmi8658c provides a driver for the QMI8658C accelerometer and gyroscope
|
||||
// made by QST Solutions.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf
|
||||
package qmi8656c
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// Device wraps the I2C connection to the QMIC8658 sensor
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
AccLsbDiv uint16
|
||||
GyroLsbDiv uint16
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// SPI Config
|
||||
SPIMode byte // One of SPI_X_WIRE
|
||||
SPIEndian byte // One of SPI_XXX_ENDIAN
|
||||
SPIAutoInc byte // One of SPI_NOT_AUTO_INC or SPI_AUTO_INC
|
||||
// Accelerometer
|
||||
AccEnable byte // One of ACC_ENABLE or ACC_DISABLE
|
||||
AccScale byte // One of ACC_XG
|
||||
AccRate byte // One of ACC_XX_YYHZ
|
||||
AccLowPass byte // One of ACC_LOW_PASS_X
|
||||
// Gyro
|
||||
GyroEnable byte // One of GYRO_X_ENABLE or GYRO_DISABLE
|
||||
GyroScale byte // One of GYRO_XDPS
|
||||
GyroRate byte // One of GYRO_X_YHZ
|
||||
GyroLowPass byte // One of GYRO_LOW_PASS_X
|
||||
}
|
||||
|
||||
// Create a new device with the I2C passed, correct address and nil values for
|
||||
// AccLsbDiv and GyroLsbDiv, which will be corrected based on the config.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus,
|
||||
Address,
|
||||
1,
|
||||
1,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the device is connected by calling WHO_AM_I and checking the
|
||||
// default identifier.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.ReadRegister(WHO_AM_I, data)
|
||||
return data[0] == IDENTIFIER
|
||||
}
|
||||
|
||||
// Create a basic default configuration that works with the "WaveShare RP2040
|
||||
// Round LCD 1.28in".
|
||||
func DefaultConfig() (cfg Config) {
|
||||
return Config{
|
||||
SPIMode: SPI_4_WIRE,
|
||||
SPIEndian: SPI_BIG_ENDIAN,
|
||||
SPIAutoInc: SPI_AUTO_INC,
|
||||
AccEnable: ACC_ENABLE,
|
||||
AccScale: ACC_8G,
|
||||
AccRate: ACC_NORMAL_1000HZ,
|
||||
AccLowPass: ACC_LOW_PASS_2_62,
|
||||
GyroEnable: GYRO_FULL_ENABLE,
|
||||
GyroScale: GYRO_512DPS,
|
||||
GyroRate: GYRO_1000HZ,
|
||||
GyroLowPass: GYRO_LOW_PASS_2_62,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user has defined a desired configuration, if not uses the
|
||||
// DefaultConfig, then defines the AccLsbDiv and GyroLsbDiv based on the
|
||||
// configurations and, finally, send the commands and configure the IMU.
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
if cfg == (Config{}) {
|
||||
cfg = DefaultConfig()
|
||||
}
|
||||
var val uint16
|
||||
// Setting accelerometer LSB
|
||||
switch cfg.AccScale {
|
||||
case ACC_2G:
|
||||
d.AccLsbDiv = 1 << 14
|
||||
case ACC_4G:
|
||||
d.AccLsbDiv = 1 << 13
|
||||
case ACC_8G:
|
||||
d.AccLsbDiv = 1 << 12
|
||||
case ACC_16G:
|
||||
d.AccLsbDiv = 1 << 11
|
||||
default:
|
||||
d.AccLsbDiv = 1 << 12
|
||||
}
|
||||
// Setting gyro LSB
|
||||
switch cfg.GyroScale {
|
||||
case GYRO_16DPS:
|
||||
d.GyroLsbDiv = 2048
|
||||
case GYRO_32DPS:
|
||||
d.GyroLsbDiv = 1024
|
||||
case GYRO_64DPS:
|
||||
d.GyroLsbDiv = 512
|
||||
case GYRO_128DPS:
|
||||
d.GyroLsbDiv = 256
|
||||
case GYRO_256DPS:
|
||||
d.GyroLsbDiv = 128
|
||||
case GYRO_512DPS:
|
||||
d.GyroLsbDiv = 64
|
||||
case GYRO_1024DPS:
|
||||
d.GyroLsbDiv = 32
|
||||
case GYRO_2048DPS:
|
||||
d.GyroLsbDiv = 16
|
||||
default:
|
||||
d.GyroLsbDiv = 64
|
||||
}
|
||||
// SPI Modes
|
||||
val = uint16((cfg.SPIMode | cfg.SPIEndian | cfg.SPIAutoInc))
|
||||
d.WriteRegister(CTRL1, val)
|
||||
// Accelerometer config
|
||||
val = uint16(cfg.AccScale | cfg.AccRate)
|
||||
d.WriteRegister(CTRL2, val)
|
||||
// Gyro config
|
||||
val = uint16(cfg.GyroScale | cfg.GyroRate)
|
||||
d.WriteRegister(CTRL3, val)
|
||||
// Sensor DSP config
|
||||
val = uint16(cfg.GyroLowPass | cfg.AccLowPass)
|
||||
d.WriteRegister(CTRL5, val)
|
||||
// Sensors config
|
||||
val = uint16(cfg.GyroEnable | cfg.AccEnable)
|
||||
d.WriteRegister(CTRL7, val)
|
||||
}
|
||||
|
||||
// Read the acceleration from the sensor, the values returned are in mg
|
||||
// (milli gravity), which means that 1000 = 1g.
|
||||
func (d *Device) ReadAcceleration() (x int32, y int32, z int32) {
|
||||
data := make([]byte, 6)
|
||||
raw := make([]int32, 3)
|
||||
d.ReadRegister(ACC_XOUT_L, data)
|
||||
for i := range raw {
|
||||
raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
|
||||
if raw[i] >= 32767 {
|
||||
raw[i] = raw[i] - 65535
|
||||
}
|
||||
}
|
||||
x = -raw[0] * 1000 / int32(d.AccLsbDiv)
|
||||
y = -raw[1] * 1000 / int32(d.AccLsbDiv)
|
||||
z = -raw[2] * 1000 / int32(d.AccLsbDiv)
|
||||
return x, y, z
|
||||
}
|
||||
|
||||
// Read the rotation from the sensor, the values returned are in mdeg/sec
|
||||
// (milli degress/second), which means that a full rotation is 360000.
|
||||
func (d *Device) ReadRotation() (x int32, y int32, z int32) {
|
||||
data := make([]byte, 6)
|
||||
raw := make([]int32, 3)
|
||||
d.ReadRegister(GYRO_XOUT_L, data)
|
||||
for i := range raw {
|
||||
raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
|
||||
if raw[i] >= 32767 {
|
||||
raw[i] = raw[i] - 65535
|
||||
}
|
||||
}
|
||||
x = raw[0] * 1000 / int32(d.GyroLsbDiv)
|
||||
y = raw[1] * 1000 / int32(d.GyroLsbDiv)
|
||||
z = raw[2] * 1000 / int32(d.GyroLsbDiv)
|
||||
return x, y, z
|
||||
}
|
||||
|
||||
// Read the temperature from the sensor, the values returned are in
|
||||
// millidegrees Celsius.
|
||||
func (d *Device) ReadTemperature() (int32, error) {
|
||||
data := make([]byte, 2)
|
||||
err := d.ReadRegister(TEMP_OUT_L, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
raw := uint16(data[1])<<8 | uint16(data[0])
|
||||
t := int32(raw) * 1000 / 256
|
||||
return t, err
|
||||
}
|
||||
|
||||
// Convenience method to read the register and avoid repetition.
|
||||
func (d *Device) ReadRegister(reg uint8, buf []byte) error {
|
||||
return d.bus.ReadRegister(uint8(d.Address), reg, buf)
|
||||
}
|
||||
|
||||
// Convenience method to write the register and avoid repetition.
|
||||
func (d *Device) WriteRegister(reg uint8, v uint16) error {
|
||||
data := []byte{byte(v)}
|
||||
err := d.bus.WriteRegister(uint8(d.Address), reg, data)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package qmi8656c
|
||||
|
||||
// The I2C address that the sensor listens to.
|
||||
const Address = 0x6B
|
||||
|
||||
const (
|
||||
// Who am I
|
||||
WHO_AM_I = 0x00
|
||||
IDENTIFIER = 0x05
|
||||
|
||||
// Configuration registers
|
||||
CTRL1 = 0x02 // SPI Modes
|
||||
CTRL2 = 0x03 // Accelerometer config
|
||||
CTRL3 = 0x04 // Gyro config
|
||||
CTRL4 = 0x05 // Magnetometer config (ignored)
|
||||
CTRL5 = 0x06 // Sensor DSP config
|
||||
CTRL6 = 0x07 // Motion on Demand (ignored)
|
||||
CTRL7 = 0x08 // Sensors config
|
||||
|
||||
// Interface config (CTRL1)
|
||||
SPI_4_WIRE = 0x00
|
||||
SPI_3_WIRE = 0x80
|
||||
SPI_NOT_AUTO_INC = 0x00
|
||||
SPI_AUTO_INC = 0x40
|
||||
SPI_LITTLE_ENDIAN = 0x00
|
||||
SPI_BIG_ENDIAN = 0x20
|
||||
|
||||
// Accelerometer scale config (CTRL2-H)
|
||||
ACC_SELF_TEST = 0x80
|
||||
|
||||
// Accelerometer scale config (CTRL2-H)
|
||||
ACC_2G = 0x00
|
||||
ACC_4G = 0x10
|
||||
ACC_8G = 0x20
|
||||
ACC_16G = 0x30
|
||||
|
||||
// Accelerometer output data rate (ODR) config (CTRL2-L)
|
||||
ACC_NORMAL_8000HZ = 0x00
|
||||
ACC_NORMAL_4000HZ = 0x01
|
||||
ACC_NORMAL_2000HZ = 0x02
|
||||
ACC_NORMAL_1000HZ = 0x03
|
||||
ACC_NORMAL_500HZ = 0x04
|
||||
ACC_NORMAL_250HZ = 0x05
|
||||
ACC_NORMAL_125HZ = 0x06
|
||||
ACC_NORMAL_62HZ = 0x07
|
||||
ACC_NORMAL_31HZ = 0x08
|
||||
ACC_LOW_POWER_128HZ = 0x0C
|
||||
ACC_LOW_POWER_21HZ = 0x0D
|
||||
ACC_LOW_POWER_11HZ = 0x0E
|
||||
ACC_LOW_POWER_3HZ = 0x0F
|
||||
|
||||
// Gyro scale config (CTRL3-H)
|
||||
GYRO_SELF_TEST = 0x80
|
||||
|
||||
// Gyro scale config (CTRL3-H)
|
||||
GYRO_16DPS = 0x00
|
||||
GYRO_32DPS = 0x10
|
||||
GYRO_64DPS = 0x20
|
||||
GYRO_128DPS = 0x30
|
||||
GYRO_256DPS = 0x40
|
||||
GYRO_512DPS = 0x50
|
||||
GYRO_1024DPS = 0x60
|
||||
GYRO_2048DPS = 0x70
|
||||
|
||||
// Gyro output data rate (ODR) config (CTRL3-L)
|
||||
GYRO_8000HZ = 0x00
|
||||
GYRO_4000HZ = 0x01
|
||||
GYRO_2000HZ = 0x02
|
||||
GYRO_1000HZ = 0x03
|
||||
GYRO_500HZ = 0x04
|
||||
GYRO_250HZ = 0x05
|
||||
GYRO_125HZ = 0x06
|
||||
GYRO_62HZ = 0x07
|
||||
GYRO_31HZ = 0x08
|
||||
|
||||
// Gyro DSP config (CTRL4-H)
|
||||
GYRO_LOW_PASS_OFF = 0x00 // Disabled
|
||||
GYRO_LOW_PASS_2_62 = 0x10 // 2.62% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_3_59 = 0x30 // 3.59% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_5_32 = 0x50 // 5.32% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_14 = 0x70 // 14% of output data rate (ODR)
|
||||
|
||||
// Accelerometer DSP config (CTRL4-L)
|
||||
ACC_LOW_PASS_OFF = 0x00 // Disabled
|
||||
ACC_LOW_PASS_2_62 = 0x01 // 2.62% of output data rate (ODR)
|
||||
ACC_LOW_PASS_3_59 = 0x03 // 3.59% of output data rate (ODR)
|
||||
ACC_LOW_PASS_5_32 = 0x05 // 5.32% of output data rate (ODR)
|
||||
ACC_LOW_PASS_14 = 0x07 // 14% of output data rate (ODR)
|
||||
|
||||
// Motion on demand (MOD) (CTRL6)
|
||||
MOD_DISABLE = 0x00
|
||||
MOD_ENABLE = 0x80
|
||||
|
||||
// Enable sensors (CTRL7)
|
||||
GYRO_DISABLE = 0x00
|
||||
GYRO_FULL_ENABLE = 0x02
|
||||
GYRO_SNOOZE_ENABLE = 0x12
|
||||
ACC_DISABLE = 0x00
|
||||
ACC_ENABLE = 0x01
|
||||
|
||||
// Timestamp Outputs Register Adresses
|
||||
TIMESTAMP_OUT_L = 0x30
|
||||
TIMESTAMP_OUT_M = 0x31
|
||||
TIMESTAMP_OUT_H = 0x32
|
||||
|
||||
// Temperature Outputs Register Adresses
|
||||
TEMP_OUT_L = 0x33
|
||||
TEMP_OUT_H = 0x34
|
||||
|
||||
// Acceleration Outputs Register Adresses
|
||||
ACC_XOUT_L = 0x35
|
||||
ACC_XOUT_H = 0x36
|
||||
ACC_YOUT_L = 0x37
|
||||
ACC_YOUT_H = 0x38
|
||||
ACC_ZOUT_L = 0x39
|
||||
ACC_ZOUT_H = 0x3A
|
||||
|
||||
// Angular Rate Outputs Register Adresses
|
||||
GYRO_XOUT_L = 0x3B
|
||||
GYRO_XOUT_H = 0x3C
|
||||
GYRO_YOUT_L = 0x3D
|
||||
GYRO_YOUT_H = 0x3E
|
||||
GYRO_ZOUT_L = 0x3F
|
||||
GYRO_ZOUT_H = 0x40
|
||||
|
||||
// Quaternion Outputs Register Adresses
|
||||
DELTA_QUAT_WOUT_L = 0x49
|
||||
DELTA_QUAT_WOUT_H = 0x4A
|
||||
DELTA_QUAT_XOUT_L = 0x4B
|
||||
DELTA_QUAT_XOUT_H = 0x4C
|
||||
DELTA_QUAT_YOUT_L = 0x4D
|
||||
DELTA_QUAT_YOUT_H = 0x4E
|
||||
DELTA_QUAT_ZOUT_L = 0x4F
|
||||
DELTA_QUAT_ZOUT_H = 0x50
|
||||
|
||||
// Delta Velocity Outputs Register Adresses
|
||||
DELTA_VEL_XOUT_L = 0x51
|
||||
DELTA_VEL_XOUT_H = 0x52
|
||||
DELTA_VEL_YOUT_L = 0x53
|
||||
DELTA_VEL_YOUT_H = 0x54
|
||||
DELTA_VEL_ZOUT_L = 0x55
|
||||
DELTA_VEL_ZOUT_H = 0x56
|
||||
)
|
||||
Reference in New Issue
Block a user