Compare commits

...

22 Commits

Author SHA1 Message Date
deadprogram 90a13a697b release: prepare for v0.18.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-18 15:25:24 +01:00
deadprogram d632eb888f docs: add LSM9DS1 to list
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-18 11:39:27 +01:00
Yurii Soldak f6761a9079 lsm9ds1: minimal implementation 2021-11-18 11:36:16 +01:00
sago35 51c3aa271b axp192: add support for AXP192 single Cell Li-Battery and power system management IC 2021-11-18 11:18:30 +01:00
soypat 520234e9f8 mcp3008: fix bitshift bug 2021-11-14 18:10:48 +01:00
Yurii Soldak 334ed57373 wifinina: control nina pins, for example leds 2021-11-12 15:32:21 +01:00
Sam Lader 3637033fec Fix broken link for SHT3x datasheet (#327)
docs: fix broken link for SHT3x datasheet
2021-11-06 21:26:08 +01:00
deadprogram 233866443c docs: update list of supported drivers with recent additions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-06 18:34:08 +01:00
Alan Wang 65fd7aa1a1 Add support for APDS-9960, Digital Proximity, Ambient Light, RGB and Gesture Sensor (#308)
apds9960: add support for apds9960
2021-11-06 11:22:39 +01:00
Alan Wang 82e9e4a7f3 Add support for LPS22HB MEMS nano pressure sensor (#297)
lps22hb: add support for lps22hb
2021-11-06 11:14:21 +01:00
deadprogram 76ff632134 hts221: update build tags for Go 1.17+
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-06 11:05:25 +01:00
Alan Wang cd2694e85f Add support for HTS221 capacitive digital sensor for relative humidity and temperature (#295)
hts221: Add support for hts221.go
2021-11-06 11:02:30 +01:00
sago35 734adb6df8 i2csoft: fix Configure() 2021-11-04 15:02:21 +01:00
sago35 2492fcb322 i2csoft: gofmt 2021-11-04 15:02:21 +01:00
sago35 4f82c231cb i2csoft: add source code for each target 2021-11-04 15:02:21 +01:00
sago35 2c9a05a413 i2csoft: remove the return value 2021-11-04 15:02:21 +01:00
sago35 a89a26112e i2csoft: fix baudrate handling 2021-11-04 15:02:21 +01:00
sago35 bd42656644 i2csoft: add support for software I2C 2021-11-04 15:02:21 +01:00
Ayke van Laethem 94729a4f7d ws2812: add support for RISC-V
This commit adds support for two new chips using the RISC-V
architecture: the FE310 (used in the HiFive 1) and the ESP32-C3 from
Espressif.
2021-11-03 19:14:32 +01:00
Ayke van Laethem 050cf4dbbc ws2812: make assembly generator architecture independent 2021-11-03 19:14:32 +01:00
sago35 49c8810432 ili9341: refactor examples/ili9341 2021-10-31 20:12:50 +01:00
Yurii Soldak 4b38841f71 net: fix raddr of tcp conn 2021-10-26 11:22:45 +02:00
66 changed files with 4231 additions and 361 deletions
+32
View File
@@ -1,3 +1,35 @@
0.18.0
---
- **new devices**
- apds9960: add support for APDS-9960 Digital Proximity sensor
- axp192: add support for AXP192 single Cell Li-Battery and power system management IC
- hts221: add support for HTS221 capacitive digital sensor for relative humidity and temperature
- i2csoft: add support for software I2C
- image: add support for image/jpeg and image/png
- lps22hb: add support for LPS22HB MEMS nano pressure sensor
- lsm6dox: add support for lsm6dox accelerometer
- lsm9ds1: add support for lsm9ds1 accelerometer
- **enhancements**
- ili9341: change to use drivers.SPI interface
- **ws2812**
- generate assembly instead of handwriting it
- improve timings to be compatible with the WS2811
- add support for 168MHz (e.g. Adafruit Feather STM32F405)
- add support for RISC-V
- wifinina: control nina pins, for example leds
- **docs**
- rtl8720dn: examples for tcpclient, udpstation, mqtt, and webserver
- **wifinina**
- nina-fw update docs
- examples/wifinina/http-get
- ili9341: refactor examples
- Fix broken link for SHT3x datasheet
- **core**
- all: use build directives for both Go1.17 and earlier versions
- **bugfixes**
- net: fix raddr of tcp conn
- mcp3008: fix bitshift bug
0.17.1
---
- To correct an error in the release process. Same as 0.17.0.
+11 -1
View File
@@ -17,6 +17,8 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
@@ -63,6 +65,8 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/hd44780i2c/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/hts221/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hub75/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic
@@ -79,6 +83,8 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
@@ -205,12 +211,16 @@ endif
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/mqttsub/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
@md5sum ./build/test.hex
DRIVERS = $(wildcard */)
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
unit-test:
+12 -4
View File
@@ -52,7 +52,7 @@ func main() {
## Currently supported devices
The following 67 devices are supported.
The following 74 devices are supported.
| Device Name | Interface Type |
|----------|-------------|
@@ -61,7 +61,9 @@ The following 67 devices are supported.
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
| [APDS9960 Digital proximity, ambient light, RGB and gesture sensor](https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf) | I2C |
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
| [AXP192 single Cell Li-Battery and Power System Management](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf) | I2C |
| [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO |
| [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C |
| [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C |
@@ -79,7 +81,9 @@ The following 67 devices are supported.
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
| [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO |
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
| [HTS221 digital humidity and temperature sensor](https://www.st.com/resource/en/datasheet/hts221.pdf) | I2C |
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
| [software I2C driver](https://www.ti.com/lit/an/slva704/slva704.pdf) | GPIO |
| [ILI9341 TFT color display](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) | SPI |
| [INA260 Volt/Amp/Power meter](https://www.ti.com/lit/ds/symlink/ina260.pdf) | I2C |
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
@@ -87,12 +91,16 @@ The following 67 devices are supported.
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
| [LIS2MDL magnetometer](https://www.st.com/resource/en/datasheet/lis2mdl.pdf) | I2C |
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
| [LPS22HB MEMS nano pressure sensor](https://www.st.com/resource/en/datasheet/dm00140895.pdf) | I2C |
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C |
| [LSM6DSOX accelerometer](https://www.st.com/resource/en/datasheet/lsm6dsox.pdf) | I2C |
| [LSM303AGR accelerometer](https://www.st.com/resource/en/datasheet/lsm303agr.pdf) | I2C |
| [LSM9DS1 accelerometer](https://www.st.com/resource/en/datasheet/lsm9ds1.pdf) | I2C |
| [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C |
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
@@ -105,7 +113,7 @@ The following 67 devices are supported.
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
+461
View File
@@ -0,0 +1,461 @@
// Package apds9960 implements a driver for APDS-9960,
// a digital proximity, ambient light, RGB and gesture sensor.
//
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
//
package apds9960
import (
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a APDS-9960 device.
type Device struct {
bus drivers.I2C
Address uint8
mode uint8
gesture gestureData
}
// Configuration for APDS-9960 device.
type Configuration struct {
ProximityPulseLength uint8
ProximityPulseCount uint8
GesturePulseLength uint8
GesturePulseCount uint8
ProximityGain uint8
GestureGain uint8
ColorGain uint8
ADCIntegrationCycles uint16
LEDBoost uint16
threshold uint8
sensitivity uint8
}
// for gesture-related data
type gestureData struct {
detected uint8
threshold uint8
sensitivity uint8
gXDelta int16
gYDelta int16
gXPrevDelta int16
gYPrevDelta int16
received bool
}
// for enabling various device function
type enableConfig struct {
GEN bool
PIEN bool
AIEN bool
WEN bool
PEN bool
AEN bool
PON bool
}
// Connected returns whether APDS-9960 has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
return data[0] == 0xAB
}
// Configure sets up the APDS-9960 device.
func (d *Device) Configure(cfg Configuration) {
d.DisableAll() // turn off everything
// "default" settings
if cfg.ProximityPulseLength == 0 {
cfg.ProximityPulseLength = 16
}
if cfg.ProximityPulseCount == 0 {
cfg.ProximityPulseCount = 64
}
if cfg.GesturePulseLength == 0 {
cfg.GesturePulseLength = 16
}
if cfg.GesturePulseCount == 0 {
cfg.GesturePulseCount = 64
}
if cfg.ProximityGain == 0 {
cfg.ProximityGain = 1
}
if cfg.GestureGain == 0 {
cfg.GestureGain = 1
}
if cfg.ColorGain == 0 {
cfg.ColorGain = 4
}
if cfg.ADCIntegrationCycles == 0 {
cfg.ADCIntegrationCycles = 4
}
if cfg.threshold == 0 {
d.gesture.threshold = 30
}
if cfg.sensitivity == 0 {
d.gesture.sensitivity = 20
}
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
if cfg.LEDBoost > 0 {
d.LEDBoost(cfg.LEDBoost)
}
}
// GetMode returns current engine mode
func (d *Device) GetMode() uint8 {
return d.mode
}
// DisableAll turns off the device and all functions
func (d *Device) DisableAll() {
d.enable(enableConfig{})
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
d.mode = MODE_NONE
d.gesture.detected = GESTURE_NONE
}
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
// default: 16, 64
func (d *Device) SetProximityPulse(length, count uint8) {
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
}
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
// default: 16, 64
func (d *Device) SetGesturePulse(length, count uint8) {
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
}
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
// default: 4 (~10 ms)
func (d *Device) SetADCIntegrationCycles(cycles uint16) {
if cycles > 256 {
cycles = 256
}
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
}
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
// default: 1, 1, 4
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
}
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
// default: 100
func (d *Device) LEDBoost(percent uint16) {
var v uint8
switch percent {
case 100:
v = 0
case 150:
v = 1
case 200:
v = 2
case 300:
v = 3
}
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
}
// Setthreshold sets threshold (0~255) for detecting gestures
// default: 30
func (d *Device) Setthreshold(t uint8) {
d.gesture.threshold = t
}
// Setsensitivity sets sensivity (0~100) for detecting gestures
// default: 20
func (d *Device) Setsensitivity(s uint8) {
if s > 100 {
s = 100
}
d.gesture.sensitivity = 100 - s
}
// EnableProximity starts the proximity engine
func (d *Device) EnableProximity() {
if d.mode != MODE_NONE {
d.DisableAll()
}
d.enable(enableConfig{PON: true, PEN: true, WEN: true})
d.mode = MODE_PROXIMITY
}
// ProximityAvailable reports if proximity data is available
func (d *Device) ProximityAvailable() bool {
if d.mode == MODE_PROXIMITY && d.readStatus("PVALID") {
return true
}
return false
}
// ReadProximity reads proximity data (0~255)
func (d *Device) ReadProximity() (proximity int32) {
if d.mode != MODE_PROXIMITY {
return 0
}
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
return 255 - int32(data[0])
}
// EnableColor starts the color engine
func (d *Device) EnableColor() {
if d.mode != MODE_NONE {
d.DisableAll()
}
d.enable(enableConfig{PON: true, AEN: true, WEN: true})
d.mode = MODE_COLOR
}
// ColorAvailable reports if color data is available
func (d *Device) ColorAvailable() bool {
if d.mode == MODE_COLOR && d.readStatus("AVALID") {
return true
}
return false
}
// ReadColor reads color data (red, green, blue, clear color/brightness)
func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
if d.mode != MODE_COLOR {
return
}
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
r = int32(uint16(data[3])<<8 | uint16(data[2]))
g = int32(uint16(data[5])<<8 | uint16(data[4]))
b = int32(uint16(data[7])<<8 | uint16(data[6]))
return
}
// EnableGesture starts the gesture engine
func (d *Device) EnableGesture() {
if d.mode != MODE_NONE {
d.DisableAll()
}
d.enable(enableConfig{PON: true, PEN: true, GEN: true, WEN: true})
d.mode = MODE_GESTURE
d.gesture.detected = GESTURE_NONE
d.gesture.gXDelta = 0
d.gesture.gYDelta = 0
d.gesture.gXPrevDelta = 0
d.gesture.gYPrevDelta = 0
d.gesture.received = false
}
// GestureAvailable reports if gesture data is available
func (d *Device) GestureAvailable() bool {
if d.mode != MODE_GESTURE {
return false
}
data := []byte{0, 0, 0, 0}
// check GVALID
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
if data[0]&0x01 == 0 {
return false
}
// get number of data sets available in FIFO
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
availableDataSets := data[0]
if availableDataSets == 0 {
return false
}
// read up, down, left and right proximity data from FIFO
var dataSets [32][4]uint8
for i := uint8(0); i < availableDataSets; i++ {
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
for j := uint8(0); j < 4; j++ {
dataSets[i][j] = data[j]
}
}
// gesture detection process
d.gesture.detected = GESTURE_NONE
for i := uint8(0); i < availableDataSets; i++ {
U := dataSets[i][0]
D := dataSets[i][1]
L := dataSets[i][2]
R := dataSets[i][3]
// if all readings fall below threshold, it's possible that
// a movement's just been made
if U < d.gesture.threshold && D < d.gesture.threshold && L < d.gesture.threshold && R < d.gesture.threshold {
d.gesture.received = true
// if there were movement in the previous step (including the last data sets)
if d.gesture.gXPrevDelta != 0 && d.gesture.gYPrevDelta != 0 {
totalX := d.gesture.gXPrevDelta - d.gesture.gXDelta
totalY := d.gesture.gYPrevDelta - d.gesture.gYDelta
// if previous and current movement are in opposite directions (pass through one led then next)
// and the difference is big enough, the gesture is recorded
switch {
case totalX < -int16(d.gesture.sensitivity):
d.gesture.detected = GESTURE_LEFT
case totalX > int16(d.gesture.sensitivity):
d.gesture.detected = GESTURE_RIGHT
case totalY > int16(d.gesture.sensitivity):
d.gesture.detected = GESTURE_DOWN
case totalY < -int16(d.gesture.sensitivity):
d.gesture.detected = GESTURE_UP
}
d.gesture.gXDelta = 0
d.gesture.gYDelta = 0
d.gesture.gXPrevDelta = 0
d.gesture.gYPrevDelta = 0
}
continue
}
// recording current movement
d.gesture.gXDelta = int16(R) - int16(L)
d.gesture.gYDelta = int16(D) - int16(U)
if d.gesture.received {
d.gesture.received = false
d.gesture.gXPrevDelta = d.gesture.gXDelta
d.gesture.gYPrevDelta = d.gesture.gYDelta
}
}
return d.gesture.detected != GESTURE_NONE
}
// ReadGesture reads last gesture data
func (d *Device) ReadGesture() (gesture int32) {
return int32(d.gesture.detected)
}
// private functions
func (d *Device) enable(cfg enableConfig) {
var gen, pien, aien, wen, pen, aen, pon uint8
if cfg.GEN {
gen = 1
}
if cfg.PIEN {
pien = 1
}
if cfg.AIEN {
aien = 1
}
if cfg.WEN {
wen = 1
}
if cfg.PEN {
pen = 1
}
if cfg.AEN {
aen = 1
}
if cfg.PON {
pon = 1
}
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
if cfg.PON {
time.Sleep(time.Millisecond * 10)
}
}
func (d *Device) readStatus(param string) bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
switch param {
case "CPSAT":
return data[0]>>7&0x01 == 1
case "PGSAT":
return data[0]>>6&0x01 == 1
case "PINT":
return data[0]>>5&0x01 == 1
case "AINT":
return data[0]>>4&0x01 == 1
case "PVALID":
return data[0]>>1&0x01 == 1
case "AVALID":
return data[0]&0x01 == 1
default:
return false
}
}
func getPulseLength(l uint8) uint8 {
switch l {
case 4:
return 0
case 8:
return 1
case 16:
return 2
case 32:
return 3
default:
return 0
}
}
func getPulseCount(c uint8) uint8 {
if c < 1 && c > 64 {
return 0
}
return c - 1
}
func getProximityGain(g uint8) uint8 {
switch g {
case 1:
return 0
case 2:
return 1
case 4:
return 2
case 8:
return 3
default:
return 0
}
}
func getALSGain(g uint8) uint8 {
switch g {
case 1:
return 0
case 4:
return 1
case 16:
return 2
case 64:
return 3
default:
return 0
}
}
+14
View File
@@ -0,0 +1,14 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package apds9960
import "tinygo.org/x/drivers"
// New creates a new APDS-9960 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
}
+29
View File
@@ -0,0 +1,29 @@
//go:build nano_33_ble
// +build nano_33_ble
package apds9960
import (
"machine"
"time"
"tinygo.org/x/drivers"
)
// New creates a new APDS-9960 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
// and wait a moment.
ENV := machine.P0_22
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
ENV.High()
R := machine.P1_00
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
R.High()
time.Sleep(time.Millisecond * 10)
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
}
+78
View File
@@ -0,0 +1,78 @@
package apds9960
const (
// I2C address
ADPS9960_ADDRESS = 0x39
// control/status registers
APDS9960_RAM_REG = 0x00
APDS9960_ENABLE_REG = 0x80
APDS9960_ATIME_REG = 0x81
APDS9960_WTIME_REG = 0x83
APDS9960_AILTIL_REG = 0x84
APDS9960_AILTH_REG = 0x85
APDS9960_AIHTL_REG = 0x86
APDS9960_AIHTH_REG = 0x87
APDS9960_PILT_REG = 0x89
APDS9960_PIHT_REG = 0x8B
APDS9960_PERS_REG = 0x8C
APDS9960_CONFIG1_REG = 0x8D
APDS9960_PPULSE_REG = 0x8E
APDS9960_CONTROL_REG = 0x8F
APDS9960_CONFIG2_REG = 0x90
APDS9960_ID_REG = 0x92
APDS9960_STATUS_REG = 0x93
APDS9960_CDATAL_REG = 0x94
APDS9960_CDATAH_REG = 0x95
APDS9960_RDATAL_REG = 0x96
APDS9960_RDATAH_REG = 0x97
APDS9960_GDATAL_REG = 0x98
APDS9960_GDATAH_REG = 0x99
APDS9960_BDATAL_REG = 0x9A
APDS9960_BDATAH_REG = 0x9B
APDS9960_PDATA_REG = 0x9C
APDS9960_POFFSET_UR_REG = 0x9D
APDS9960_POFFSET_DL_REG = 0x9E
APDS9960_CONFIG3_REG = 0x9F
APDS9960_GPENTH_REG = 0xA0
APDS9960_GEXTH_REG = 0xA1
APDS9960_GCONF1_REG = 0xA2
APDS9960_GCONF2_REG = 0xA3
APDS9960_GOFFSET_U_REG = 0xA4
APDS9960_GOFFSET_D_REG = 0xA5
APDS9960_GOFFSET_L_REG = 0xA7
APDS9960_GOFFSET_R_REG = 0xA9
APDS9960_GPULSE_REG = 0xA6
APDS9960_GCONF3_REG = 0xAA
APDS9960_GCONF4_REG = 0xAB
APDS9960_GFLVL_REG = 0xAE
APDS9960_GSTATUS_REG = 0xAF
APDS9960_IFORCE_REG = 0xE4
APDS9960_PICLEAR_REG = 0xE5
APDS9960_CICLEAR_REG = 0xE6
APDS9960_AICLEAR_REG = 0xE7
APDS9960_GFIFO_U_REG = 0xFC
APDS9960_GFIFO_D_REG = 0xFD
APDS9960_GFIFO_L_REG = 0xFE
APDS9960_GFIFO_R_REG = 0xFF
)
const (
// sensor modes
MODE_NONE = iota
MODE_PROXIMITY
MODE_COLOR
MODE_GESTURE
)
const (
// detected gestures
GESTURE_NONE = iota
GESTURE_UP
GESTURE_DOWN
GESTURE_LEFT
GESTURE_RIGHT
)
+258
View File
@@ -0,0 +1,258 @@
// Package axp192 provides a driver for the axp192 I2C Enhanced single Cell
// Li-Battery and Power System Management IC.
//
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
//
package axp192 // import "tinygo.org/x/drivers/axp192"
import (
"tinygo.org/x/drivers"
)
type Error uint8
const (
ErrInvalidID Error = 0x1
)
func (e Error) Error() string {
switch e {
case ErrInvalidID:
return "Invalid chip ID"
default:
return "Unknown error"
}
}
type Device struct {
bus drivers.I2C
buf []byte
Address uint8
}
// New returns AXP192 device for the provided I2C bus using default address.
func New(i2c drivers.I2C) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 2),
Address: Address,
}
}
type Config struct {
}
// Configure the AXP192 device.
func (d *Device) Configure(config Config) error {
return nil
}
// ReadPowerSupplyStatus reads power supply status.
func (d *Device) ReadPowerSupplyStatus() uint8 {
return d.read8bit(RegPowerSupplyStatus)
}
// SetVbusIPSOutAccessManagement sets VBUS-IPSOUT access management.
func (d *Device) SetVbusIPSOutAccessManagement(a uint8) {
d.write1Byte(RegVbusIPSOutAccessManagement, a)
}
// GetVbusIPSOutAccessManagement gets VBUS-IPSOUT access management.
func (d *Device) GetVbusIPSOutAccessManagement() uint8 {
return d.read8bit(RegVbusIPSOutAccessManagement)
}
// SetGPIO1Control sets GPIO1 function.
func (d *Device) SetGPIO1Control(a uint8) {
d.write1Byte(RegGPIO1Control, a)
}
// GetGPIO1Control gets GPIO1 function.
func (d *Device) GetGPIO1Control() uint8 {
return d.read8bit(RegGPIO1Control)
}
// SetGPIO2Control sets GPIO2 function.
func (d *Device) SetGPIO2Control(a uint8) {
d.write1Byte(RegGPIO2Control, a)
}
// GetGPIO2Control gets GPIO2 function.
func (d *Device) GetGPIO2Control() uint8 {
return d.read8bit(RegGPIO2Control)
}
// SetGPIO20SignalStatus sets GPIO[2:0] signal status.
func (d *Device) SetGPIO20SignalStatus(a uint8) {
d.write1Byte(RegGPIO20SignalStatus, a)
}
// GetGPIO20SignalStatus gets GPIO[2:0] signal status.
func (d *Device) GetGPIO20SignalStatus() uint8 {
return d.read8bit(RegGPIO20SignalStatus)
}
// SetBackupBatteryChargingControl sets backup battery charge control.
func (d *Device) SetBackupBatteryChargingControl(a uint8) {
d.write1Byte(RegBackupBatteryChargingControl, a)
}
// GetBackupBatteryChargingControl gets backup battery charge control.
func (d *Device) GetBackupBatteryChargingControl() uint8 {
return d.read8bit(RegBackupBatteryChargingControl)
}
// SetDCDC1VoltageSet sets DC-DC1 output voltage.
func (d *Device) SetDCDC1VoltageSet(a uint8) {
d.write1Byte(RegDCDC1VoltageSet, a)
}
// GetDCDC1VoltageSet gets DC-DC1 output voltage.
func (d *Device) GetDCDC1VoltageSet() uint8 {
return d.read8bit(RegDCDC1VoltageSet)
}
// SetDCDC2VoltageSet sets DC-DC2 dynamic voltage parameter.
func (d *Device) SetDCDC2VoltageSet(a uint8) {
d.write1Byte(RegDCDC2VoltageSet, a)
}
// GetDCDC2VoltageSet gets DC-DC2 dynamic voltage parameter.
func (d *Device) GetDCDC2VoltageSet() uint8 {
return d.read8bit(RegDCDC2VoltageSet)
}
// SetDCDC3VoltageSet sets DC-DC3 output voltage.
func (d *Device) SetDCDC3VoltageSet(a uint8) {
d.write1Byte(RegDCDC3VoltageSet, a)
}
// GetDCDC3VoltageSet gets DC-DC3 output voltage.
func (d *Device) GetDCDC3VoltageSet() uint8 {
return d.read8bit(RegDCDC3VoltageSet)
}
// SetLDO23VoltageSet sets LDO2/3 output voltage.
func (d *Device) SetLDO23VoltageSet(a uint8) {
d.write1Byte(RegLDO23VoltageSet, a)
}
// GetLDO23VoltageSet gets LDO2/3 output voltage.
func (d *Device) GetLDO23VoltageSet() uint8 {
return d.read8bit(RegLDO23VoltageSet)
}
// SetDCDC13LDO23Switch sets DC-DC1/3 & LOD2/3 output control.
func (d *Device) SetDCDC13LDO23Switch(a uint8) {
d.write1Byte(RegDCDC13LDO23Switch, a)
}
// GetDCDC13LDO23Switch gets DC-DC1/3 & LOD2/3 output control.
func (d *Device) GetDCDC13LDO23Switch() uint8 {
return d.read8bit(RegDCDC13LDO23Switch)
}
// SetGPIO43FunctionControl sets GPIO[4:3] pin function.
func (d *Device) SetGPIO43FunctionControl(a uint8) {
d.write1Byte(RegGPIO43FunctionControl, a)
}
// GetGPIO43FunctionControl gets GPIO[4:3] pin function.
func (d *Device) GetGPIO43FunctionControl() uint8 {
return d.read8bit(RegGPIO43FunctionControl)
}
// SetPEKParameterSet sets PEK press key parameter.
func (d *Device) SetPEKParameterSet(a uint8) {
d.write1Byte(RegPEKParameterSet, a)
}
// GetPEKParameterSet gets PEK press key parameter.
func (d *Device) GetPEKParameterSet() uint8 {
return d.read8bit(RegPEKParameterSet)
}
// SetADCEnableSet sets ADC enable 1.
func (d *Device) SetADCEnableSet(a uint8) {
d.write1Byte(RegADCEnableSet, a)
}
// GetADCEnableSet gets ADC enable 1.
func (d *Device) GetADCEnableSet() uint8 {
return d.read8bit(RegADCEnableSet)
}
// SetGPIO43SignalStatus sets GPIO[4:3] signal status.
func (d *Device) SetGPIO43SignalStatus(a uint8) {
d.write1Byte(RegGPIO43SignalStatus, a)
}
// GetGPIO43SignalStatus gets GPIO[4:3] signal status.
func (d *Device) GetGPIO43SignalStatus() uint8 {
return d.read8bit(RegGPIO43SignalStatus)
}
// SetDCVoltage sets DC voltage.
func (d *Device) SetDCVoltage(number uint8, voltage uint16) {
if voltage < 700 {
voltage = 0
} else {
voltage = (voltage - 700) / 25
}
switch number {
case 0:
v := d.GetDCDC1VoltageSet()
d.SetDCDC1VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
case 1:
v := d.GetDCDC2VoltageSet()
d.SetDCDC2VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
case 2:
v := d.GetDCDC3VoltageSet()
d.SetDCDC3VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
}
}
// SetLDOVoltage sets LDO voltage.
func (d *Device) SetLDOVoltage(number uint8, voltage uint16) {
if voltage > 3300 {
voltage = 15
} else {
voltage = (voltage / 100) - 18
}
switch number {
case 2:
v := d.GetLDO23VoltageSet()
d.SetLDO23VoltageSet((v & 0x0F) | (uint8(voltage) << 4))
break
case 3:
v := d.GetLDO23VoltageSet()
d.SetLDO23VoltageSet((v & 0xF0) | uint8(voltage))
break
}
}
// SetLDOEnable enable LDO.
func (d *Device) SetLDOEnable(number uint8, state bool) {
mark := uint8(0x01)
mark <<= number
switch number {
case 2:
v := d.GetDCDC13LDO23Switch()
d.SetDCDC13LDO23Switch(v | mark)
case 3:
v := d.GetDCDC13LDO23Switch()
d.SetDCDC13LDO23Switch(v & (^mark))
}
}
func (d *Device) write1Byte(reg, data uint8) {
d.bus.WriteRegister(d.Address, reg, []byte{data})
}
func (d *Device) read8bit(reg uint8) uint8 {
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
return d.buf[0]
}
+158
View File
@@ -0,0 +1,158 @@
package axp192
import (
"time"
"tinygo.org/x/drivers"
axp192orig "tinygo.org/x/drivers/axp192"
)
// Device wraps an I2C connection to a AXP192 device.
type Device struct {
*axp192orig.Device
LED Pin
RST Pin
SPK_EN Pin
}
// New creates a new AXP192 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(i2c drivers.I2C) *Device {
d := axp192orig.New(i2c)
axp := &Device{
Device: d,
}
axp.LED = Pin{pin: 1, axp: axp}
axp.SPK_EN = Pin{pin: 2, axp: axp}
axp.RST = Pin{pin: 4, axp: axp}
axp.begin()
return axp
}
type Config struct {
}
// Configure sets up the device for communication
func (d *Device) Configure(config Config) error {
return d.Device.Configure(axp192orig.Config{})
}
func (d *Device) begin() {
d.SetVbusIPSOutAccessManagement((d.GetVbusIPSOutAccessManagement() & 0x04) | 0x02)
d.SetGPIO1Control(d.GetGPIO1Control() & 0xF8)
d.SetGPIO2Control(d.GetGPIO2Control() & 0xF8)
d.SetBackupBatteryChargingControl((d.GetBackupBatteryChargingControl() & 0x1C) | 0xA2)
d.SetESPVoltage(3350)
d.SetLcdVoltage(3300)
d.SetLDOVoltage(2, 3300) //Periph power voltage preset (LCD_logic, SD card)
d.SetLDOVoltage(3, 2000) //Vibrator power voltage preset
d.SetLDOEnable(2, true)
d.SetDCDC3(true) // LCD Backlight
// GPIO4 : LCD Reset
d.SetGPIO43FunctionControl((d.GetGPIO43FunctionControl() & 0x72) | 0x84)
// Power On/Off Setting
d.SetPEKParameterSet(0x4C)
d.SetADCEnableSet(0xFF)
d.RST.Low()
time.Sleep(100 * time.Millisecond)
d.RST.High()
time.Sleep(100 * time.Millisecond)
}
// ToggleLED toggles LED connected to AXP192.
func (d *Device) ToggleLED() {
v := d.GetGPIO20SignalStatus()
if (v & 0x02) > 0 {
d.SetGPIO20SignalStatus(v & 0xFD)
} else {
d.SetGPIO20SignalStatus(v | 0x02)
}
}
// SetESPVoltage sets voltage of ESP32.
func (d *Device) SetESPVoltage(voltage uint16) {
if voltage >= 3000 && voltage <= 3400 {
d.SetDCVoltage(0, voltage)
}
}
// SetLcdVoltage sets voltage of LCD.
func (d *Device) SetLcdVoltage(voltage uint16) {
if voltage >= 2500 && voltage <= 3300 {
d.SetDCVoltage(2, voltage)
}
}
// SetDCDC3 enables or disables DCDC3.
func (d *Device) SetDCDC3(State bool) {
v := d.GetDCDC13LDO23Switch()
if State == true {
v = (1 << 1) | v
} else {
v = ^(uint8(1) << 1) & v
}
d.SetDCDC13LDO23Switch(v)
}
// Pin is a single pin on AXP192.
type Pin struct {
pin uint8
axp *Device
}
// High sets this GPIO pin to high.
func (p Pin) High() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
p.axp.SetGPIO20SignalStatus(v | 0x02)
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
v |= uint8(0x02)
p.axp.SetGPIO43SignalStatus(v)
}
}
// Low sets this GPIO pin to low.
func (p Pin) Low() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
p.axp.SetGPIO20SignalStatus(v & 0xFD)
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
v &= ^uint8(0x02)
p.axp.SetGPIO43SignalStatus(v)
}
}
// Toggle switches an output pin from low to high or from high to low.
func (p Pin) Toggle() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
if (v & 0x02) == 0 {
p.axp.SetGPIO20SignalStatus(v | 0x02)
} else {
p.axp.SetGPIO20SignalStatus(v & 0xFD)
}
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
if (v & 0x02) == 0 {
v |= uint8(0x02)
} else {
v &= ^uint8(0x02)
}
p.axp.SetGPIO43SignalStatus(v)
}
}
+127
View File
@@ -0,0 +1,127 @@
package axp192
// power supply control class
// 0x00 Power supply status register
// 0x01 Power supply mode/charging status register
// 0x04 OTG VBUS status register
// 0x0609 Data buffer register
// 0x10 EXTEN & DCDC2 switch register
// 0x12 DCDC1/3 & LDO2/3switch register
// 0x23 DCDC2 voltage set register
// 0x25 DCDC2 voltage slope set register
// 0x26 DCDC1voltage set register
// 0x27 DCDC3 voltage set register
// 0x28 LDO2/3 voltage set register
// 0x30 VBUSIPSOUT access set register
// 0x31 VOFF power off voltage set register
// 0x32 Power off、battery detect、CHGLED control register
// 0x33 Charging control register1
// 0x34 Charging control register2
// 0x35 Backup battery charging control register
// 0x36 PEK parameter set register
// 0x37 DCDC switch frequency set register
// 0x38 Battery charging under temperature warning set register
// 0x39 Battery charging over temperature warning set register
// 0x3A APS under voltage Level1 set register
// 0x3B APS under voltage Level2 set register
// 0x3C Battery discharging under temperature warning set register
// 0x3D Battery discharging over temperature warning set register
// 0x80 DCDC mode set register
// 0x82 ADC enable set register 1
// 0x83 ADC enable set register 2
// 0x84 ADC sample frequency set, TS pin control register
// 0x85 GPIO [3:0] input range set register
// 0x8A Timer control register
// 0x8B VBUS monitor set register
// 0x8F Over temperature power off control register
// GPIO control class
// 0x90 GPIO0 control register
// 0x91 GPIO0 LDO mode output voltage set register
// 0x92 GPIO1 control register
// 0x93 GPIO2 control register
// 0x94 GPIO[2:0] signal status register
// 0x95 GPIO[4:3] function control register
// 0x96 GPIO[4:3] signal status register
// 0x97 GPIO[2:0] pull down control register
// 0x98 PWM1 frequency set register
// 0x99 PWM1 duty ratio set register 1
// 0x9A PWM1 duty ratio set register 2
// 0x9B PWM2 frequency set register
// 0x9C PWM2 duty ratio set register 1
// 0x9D PWM2 duty ratio set register 2
// 0x9E GPIO5 control register
// IRQ control class
// 0x40 IRQ enable control register 1
// 0x41 IRQ enable control register 2
// 0x42 IRQ enable control register 3
// 0x43 IRQ enable control register 4
// 0x44 IRQ status register 1
// 0x45 IRQ status register 2
// 0x46 IRQ status register 3
// 0x47 IRQ status register 4
// ADC data class
// 0x56 ACIN voltage ADC data high 8 bit
// 0x57 ACIN voltage ADC data low 4 bit
// 0x58 ACIN current ADC data high 8 bit
// 0x59 ACIN current ADC data low 4 bit
// 0x5A VBUS voltage ADC data high 8 bit
// 0x5B VBUS voltage ADC data low 4 bit
// 0x5C VBUS current ADC data high 8 bit
// 0x5D VBUS current ADC data low 4 bit
// 0x5E AXP192 internal temperature monitor ADC data High 8 bit
// 0x5F AXP192 internal temperature monitor ADC data low 4 bit
// 0x62 TS input ADC data High 8 bitmonitor battery temperature by default
// 0x63 TS input ADC data low 4 bitmonitor battery temperature by default
// 0x64 GPIO0 voltage ADC data high 8 bit
// 0x65 GPIO0 voltage ADC data low 4 bit
// 0x66 GPIO1 voltage ADC data high 8 bit
// 0x67 GPIO1 voltage ADC data low 4 bit
// 0x68 GPIO2 voltage ADC data high 8 bit
// 0x69 GPIO2 voltage ADC data low 4 bit
// 0x6A GPIO[3] voltage ADC data high 8 bit
// 0x6B GPIO[3] voltage ADC data low 4 bit
// 0x70 Battery instantaneous power high 8 bit
// 0x71 Battery instantaneous power middle 8 bit
// 0x72 Battery instantaneous power low 8 bit
// 0x78 Battery voltage high 8 bit
// 0x79 Battery voltage low 4 bit
// 0x7A Battery charging current high 8 bit
// 0x7B Battery charging current low 5 bit
// 0x7C Battery discharging current high 8 bit
// 0x7D Battery discharging current low 5 bit
// 0x7E APS voltage high 8 bit
// 0x7F APS voltage low 4 bit
// 0xB0 Battery charging coulomb counter data register 3
// 0xB1 Battery charging coulomb counter data register 2
// 0xB2 Battery charging coulomb counter data register 1
// 0xB3 Battery charging coulomb counter data register 0
// 0xB4 Battery discharging coulomb counter data register 3
// 0xB5 Battery discharging coulomb counter data register 2
// 0xB6 Battery discharging coulomb counter data register 1
// 0xB7 Battery discharging coulomb counter data register 0
// 0xB8 Coulomb counter control register
const (
// Address is default I2C address.
Address = 0x34
RegPowerSupplyStatus = 0x00
RegDCDC13LDO23Switch = 0x12
RegVbusIPSOutAccessManagement = 0x30
RegBackupBatteryChargingControl = 0x35
RegDCDC2VoltageSet = 0x25
RegDCDC1VoltageSet = 0x26
RegDCDC3VoltageSet = 0x27
RegLDO23VoltageSet = 0x28
RegPEKParameterSet = 0x36
RegADCEnableSet = 0x82
RegGPIO1Control = 0x92
RegGPIO2Control = 0x93
RegGPIO20SignalStatus = 0x94
RegGPIO43FunctionControl = 0x95
RegGPIO43SignalStatus = 0x96
)
+38
View File
@@ -0,0 +1,38 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.Configure(apds9960.Configuration{}) // use default settings
sensor.EnableColor() // enable color engine
for {
if sensor.ColorAvailable() {
r, g, b, c := sensor.ReadColor()
println("Red =", r, "\tGreen =", g, "\tBlue =", b, "\tClear =", c)
}
time.Sleep(time.Millisecond * 100)
}
}
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.Configure(apds9960.Configuration{}) // use default settings
sensor.EnableGesture() // enable gesture engine
for {
// wave your hand (not too slow) about 10 cm above the sensor
if sensor.GestureAvailable() {
gesture := sensor.ReadGesture()
print("Detected gesture: ")
switch gesture {
case apds9960.GESTURE_UP:
println("Up")
case apds9960.GESTURE_DOWN:
println("Down")
case apds9960.GESTURE_LEFT:
println("Left")
case apds9960.GESTURE_RIGHT:
println("Right")
}
}
// note: the delay shouldn't be too long, otherwise new gesture data might be lost
time.Sleep(time.Millisecond * 250)
}
}
+38
View File
@@ -0,0 +1,38 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.Configure(apds9960.Configuration{}) // use default settings
sensor.EnableProximity() // enable proximity engine
for {
if sensor.ProximityAvailable() {
p := sensor.ReadProximity()
println("Proximity:", p)
}
time.Sleep(time.Millisecond * 100)
}
}
@@ -0,0 +1,25 @@
package main
import (
"machine"
"time"
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
"tinygo.org/x/drivers/i2csoft"
)
func main() {
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
axp := axp192.New(i2c)
led := axp.LED
for {
led.Low()
time.Sleep(time.Millisecond * 500)
led.High()
time.Sleep(time.Millisecond * 500)
}
}
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/hts221"
)
func main() {
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := hts221.New(machine.I2C1)
if !sensor.Connected() {
println("HTS221 not connected!")
return
}
sensor.Configure() // power on and calibrate
for {
h, _ := sensor.ReadHumidity()
t, _ := sensor.ReadTemperature()
println("h =", float32(h)/100.0, "% / t =", float32(t)/1000.0, "*C")
time.Sleep(time.Second)
}
}
+27
View File
@@ -0,0 +1,27 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/adt7410"
"tinygo.org/x/drivers/i2csoft"
)
func main() {
i2c := i2csoft.New(machine.SCL_PIN, machine.SDA_PIN)
i2c.Configure(i2csoft.I2CConfig{
Frequency: 400e3,
})
sensor := adt7410.New(i2c)
sensor.Configure()
for {
temp := sensor.ReadTempF()
fmt.Printf("temperature: %f\r\n", temp)
time.Sleep(time.Second)
}
}
-30
View File
@@ -1,30 +0,0 @@
//go:build atsamd21
// +build atsamd21
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI0,
machine.D0,
machine.D1,
machine.D2,
)
backlight = machine.D3
)
func init() {
machine.SPI0.Configure(machine.SPIConfig{
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Frequency: 24000000,
})
}
+6 -7
View File
@@ -2,9 +2,9 @@ package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
"tinygo.org/x/drivers/ili9341"
)
@@ -16,16 +16,15 @@ var (
green = color.RGBA{0, 255, 0, 255}
)
var (
display *ili9341.Device
)
func main() {
display = initdisplay.InitDisplay()
backlight.Configure(machine.PinConfig{machine.PinOutput})
display.Configure(ili9341.Config{})
width, height := display.Size()
display.FillScreen(black)
backlight.High()
display.FillRectangle(0, 0, width/2, height/2, white)
display.FillRectangle(width/2, 0, width/2, height/2, red)
display.FillRectangle(0, height/2, width/2, height/2, green)
-23
View File
@@ -1,23 +0,0 @@
//go:build pyportal
// +build pyportal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewParallel(
machine.LCD_DATA0,
machine.TFT_WR,
machine.TFT_DC,
machine.TFT_CS,
machine.TFT_RESET,
machine.TFT_RD,
)
backlight = machine.TFT_BACKLIGHT
)
-30
View File
@@ -1,30 +0,0 @@
//go:build wioterminal
// +build wioterminal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
backlight = machine.LCD_BACKLIGHT
)
func init() {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40000000,
})
}
+41
View File
@@ -0,0 +1,41 @@
//go:build atsamd21
// +build atsamd21
package initdisplay
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var ()
func InitDisplay() *ili9341.Device {
machine.SPI0.Configure(machine.SPIConfig{
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Frequency: 24000000,
})
// configure backlight
backlight := machine.D3
backlight.Configure(machine.PinConfig{machine.PinOutput})
display := ili9341.NewSPI(
machine.SPI0,
machine.D0,
machine.D1,
machine.D2,
)
// configure display
display.Configure(ili9341.Config{})
backlight.High()
display.SetRotation(ili9341.Rotation270)
return display
}
+34
View File
@@ -0,0 +1,34 @@
//go:build pyportal
// +build pyportal
package initdisplay
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
func InitDisplay() *ili9341.Device {
display := ili9341.NewParallel(
machine.LCD_DATA0,
machine.TFT_WR,
machine.TFT_DC,
machine.TFT_CS,
machine.TFT_RESET,
machine.TFT_RD,
)
// configure backlight
backlight := machine.TFT_BACKLIGHT
backlight.Configure(machine.PinConfig{machine.PinOutput})
// configure display
display.Configure(ili9341.Config{})
backlight.High()
display.SetRotation(ili9341.Rotation270)
return display
}
@@ -1,7 +1,7 @@
//go:build wioterminal
// +build wioterminal
package main
package initdisplay
import (
"machine"
@@ -9,22 +9,31 @@ import (
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
backlight = machine.LCD_BACKLIGHT
)
func init() {
func InitDisplay() *ili9341.Device {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40000000,
})
// configure backlight
backlight := machine.LCD_BACKLIGHT
backlight.Configure(machine.PinConfig{machine.PinOutput})
display := ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
// configure display
display.Configure(ili9341.Config{})
backlight.High()
display.SetRotation(ili9341.Rotation270)
return display
}
+6 -9
View File
@@ -3,9 +3,9 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
"tinygo.org/x/drivers/ili9341"
)
@@ -44,20 +44,17 @@ var (
palette [16]uint16
)
var (
display *ili9341.Device
)
func main() {
display = initdisplay.InitDisplay()
// configure backlight
backlight.Configure(machine.PinConfig{machine.PinOutput})
// configure display
display.Configure(ili9341.Config{})
print("width, height == ")
width, height := display.Size()
println(width, height)
backlight.High()
display.SetRotation(ili9341.Rotation270)
DrawBackground()
startTime = time.Now().UnixNano()
@@ -1,23 +0,0 @@
//go:build pyportal
// +build pyportal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewParallel(
machine.LCD_DATA0,
machine.TFT_WR,
machine.TFT_DC,
machine.TFT_CS,
machine.TFT_RESET,
machine.TFT_RD,
)
backlight = machine.TFT_BACKLIGHT
)
@@ -1,30 +0,0 @@
//go:build wioterminal
// +build wioterminal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
backlight = machine.LCD_BACKLIGHT
)
func init() {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40000000,
})
}
-30
View File
@@ -1,30 +0,0 @@
//go:build atsamd21
// +build atsamd21
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI0,
machine.D0,
machine.D1,
machine.D2,
)
backlight = machine.D3
)
func init() {
machine.SPI0.Configure(machine.SPIConfig{
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Frequency: 24000000,
})
}
+6 -7
View File
@@ -2,9 +2,9 @@ package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
"tinygo.org/x/drivers/ili9341"
)
@@ -16,16 +16,15 @@ var (
white = color.RGBA{255, 255, 255, 255}
)
var (
display *ili9341.Device
)
func main() {
display := initdisplay.InitDisplay()
backlight.Configure(machine.PinConfig{machine.PinOutput})
display.Configure(ili9341.Config{})
width, height := display.Size()
display.FillScreen(black)
backlight.High()
display.FillRectangle(0, 0, width/2, height/2, white)
display.FillRectangle(width/2, 0, width/2, height/2, red)
display.FillRectangle(0, height/2, width/2, height/2, green)
-23
View File
@@ -1,23 +0,0 @@
//go:build pyportal
// +build pyportal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewParallel(
machine.LCD_DATA0,
machine.TFT_WR,
machine.TFT_DC,
machine.TFT_CS,
machine.TFT_RESET,
machine.TFT_RD,
)
backlight = machine.TFT_BACKLIGHT
)
-30
View File
@@ -1,30 +0,0 @@
//go:build atsamd21
// +build atsamd21
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI0,
machine.D0,
machine.D1,
machine.D2,
)
backlight = machine.D3
)
func init() {
machine.SPI0.Configure(machine.SPIConfig{
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Frequency: 24000000,
})
}
+6 -5
View File
@@ -3,10 +3,10 @@ package main
import (
"fmt"
"image/color"
"machine"
"strings"
"time"
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
"tinygo.org/x/drivers/ili9341"
"tinygo.org/x/drivers/image/jpeg"
"tinygo.org/x/drivers/image/png"
@@ -20,6 +20,10 @@ var (
green = color.RGBA{0, 255, 0, 255}
)
var (
display *ili9341.Device
)
func main() {
err := run()
for err != nil {
@@ -28,9 +32,7 @@ func main() {
}
func run() error {
backlight.Configure(machine.PinConfig{machine.PinOutput})
display.Configure(ili9341.Config{})
display = initdisplay.InitDisplay()
width, height := display.Size()
if width < 320 || height < 240 {
@@ -38,7 +40,6 @@ func run() error {
}
display.FillScreen(black)
backlight.High()
for {
err := drawJpeg(display)
-23
View File
@@ -1,23 +0,0 @@
//go:build pyportal
// +build pyportal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewParallel(
machine.LCD_DATA0,
machine.TFT_WR,
machine.TFT_DC,
machine.TFT_CS,
machine.TFT_RESET,
machine.TFT_RD,
)
backlight = machine.TFT_BACKLIGHT
)
-30
View File
@@ -1,30 +0,0 @@
//go:build wioterminal
// +build wioterminal
package main
import (
"machine"
"tinygo.org/x/drivers/ili9341"
)
var (
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
backlight = machine.LCD_BACKLIGHT
)
func init() {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40000000,
})
}
+37
View File
@@ -0,0 +1,37 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/lps22hb"
)
func main() {
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := lps22hb.New(machine.I2C1)
if !sensor.Connected() {
println("LPS22HB not connected!")
return
}
sensor.Configure()
for {
p, _ := sensor.ReadPressure()
t, _ := sensor.ReadTemperature()
println("p =", float32(p)/1000.0, "hPa / t =", float32(t)/1000.0, "*C")
time.Sleep(time.Second)
// note: the device would power down itself after each query
}
}
+103
View File
@@ -0,0 +1,103 @@
// LSM9DS1, 9 axis Inertial Measurement Unit (IMU)
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/lsm9ds1"
)
const (
PLOTTER = false
SHOW_ACCELERATION = true
SHOW_ROTATION = true
SHOW_MAGNETIC_FIELD = true
SHOW_TEMPERATURE = true
)
func main() {
// I2C configure
machine.I2C0.Configure(machine.I2CConfig{})
// LSM9DS1 setup
device := lsm9ds1.New(machine.I2C0)
err := device.Configure(lsm9ds1.Configuration{
AccelRange: lsm9ds1.ACCEL_2G,
AccelSampleRate: lsm9ds1.ACCEL_SR_119,
GyroRange: lsm9ds1.GYRO_250DPS,
GyroSampleRate: lsm9ds1.GYRO_SR_119,
MagRange: lsm9ds1.MAG_4G,
MagSampleRate: lsm9ds1.MAG_SR_40,
})
if err != nil {
for {
println("Failed to configure", err.Error())
time.Sleep(time.Second)
}
}
for {
if con, err := device.Connected(); !con || err != nil {
println("LSM9DS1 not connected")
time.Sleep(time.Second)
continue
}
ax, ay, az, _ := device.ReadAcceleration()
gx, gy, gz, _ := device.ReadRotation()
mx, my, mz, _ := device.ReadMagneticField()
t, _ := device.ReadTemperature()
if PLOTTER {
printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t)
time.Sleep(time.Millisecond * 100)
} else {
printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t)
time.Sleep(time.Millisecond * 1000)
}
}
}
// Arduino IDE's Serial Plotter
func printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
if SHOW_ACCELERATION {
fmt.Printf("AX:%f, AY:%f, AZ:%f,", axis(ax), axis(ay), axis(az))
}
if SHOW_ROTATION {
fmt.Printf("GX:%f, GY:%f, GZ:%f,", axis(gx), axis(gy), axis(gz))
}
if SHOW_MAGNETIC_FIELD {
fmt.Printf("MX:%d, MY:%d, MZ:%d,", mx, my, mz)
}
if SHOW_TEMPERATURE {
fmt.Printf("T:%f", float32(t)/1000)
}
println()
}
// Any Serial Monitor
func printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
if SHOW_ACCELERATION {
fmt.Printf("Acceleration (g): %f, %f, %f\r\n", axis(ax), axis(ay), axis(az))
}
if SHOW_ROTATION {
fmt.Printf("Rotation (dps): %f, %f, %f\r\n", axis(gx), axis(gy), axis(gz))
}
if SHOW_MAGNETIC_FIELD {
fmt.Printf("Magnetic field (nT): %d, %d, %d\r\n", mx, my, mz)
}
if SHOW_TEMPERATURE {
fmt.Printf("Temperature C: %f\r\n", float32(t)/1000)
}
println()
}
func axis(raw int32) float32 {
return float32(raw) / 1000000
}
+91
View File
@@ -0,0 +1,91 @@
//go:build nano_rp2040
// +build nano_rp2040
// This examples shows how to control RGB LED connected to
// NINA-W102 chip on Arduino Nano RP2040 Connect board
// Built-in LED code added for API comparison
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/wifinina"
)
const (
LED = machine.LED
// Arduino Nano RP2040 Connect board RGB LED pins
// See https://docs.arduino.cc/static/3525d638b5c76a2d19588d6b41cd02a0/ABX00053-full-pinout.pdf
LED_R wifinina.Pin = 27
LED_G wifinina.Pin = 25
LED_B wifinina.Pin = 26
)
var (
// these are the default pins for the Arduino Nano-RP2040 Connect
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
device *wifinina.Device
)
func setup() {
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
device = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
device.Configure()
time.Sleep(time.Second)
LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
LED_R.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
LED_G.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
LED_B.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
}
func main() {
setup()
LED.Low() // OFF
LED_R.High() // OFF
LED_G.High() // OFF
LED_B.High() // OFF
go func() {
for {
LED.Low()
time.Sleep(time.Second)
LED.High()
time.Sleep(time.Second)
}
}()
for {
LED_R.Low() // ON
time.Sleep(time.Second)
LED_R.High() // OFF
LED_G.Low() // ON
time.Sleep(time.Second)
LED_G.High() // OFF
LED_B.Low() // ON
time.Sleep(time.Second)
LED_B.High() // OFF
}
}
+178
View File
@@ -0,0 +1,178 @@
// Package hts221 implements a driver for HTS221,
// a capacitive digital sensor for relative humidity and temperature.
//
// Datasheet: https://www.st.com/resource/en/datasheet/hts221.pdf
//
package hts221
import (
"errors"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a HTS221 device.
type Device struct {
bus drivers.I2C
Address uint8
humiditySlope float32
humidityZero float32
temperatureSlope float32
temperatureZero float32
}
// Connected returns whether HTS221 has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, HTS221_WHO_AM_I_REG, data)
return data[0] == 0xBC
}
// Configure sets up the HTS221 device for communication.
func (d *Device) Configure() {
// read calibration data
d.calibration()
// activate device and use block data update mode
d.Power(true)
}
// Power is for turn on/off the HTS221 device
func (d *Device) Power(status bool) {
data := []byte{0}
if status {
data[0] = 0x84
}
d.bus.WriteRegister(d.Address, HTS221_CTRL1_REG, data)
}
// ReadHumidity returns the relative humidity in percent * 100.
// Returns an error if the device is not turned on.
func (d *Device) ReadHumidity() (humidity int32, err error) {
err = d.waitForOneShot(0x02)
if err != nil {
return
}
// read data and calibrate
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG+1, data[1:])
hValue := readInt(data[1], data[0])
hValueCalib := float32(hValue)*d.humiditySlope + d.humidityZero
return int32(hValueCalib * 100), nil
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
// Returns an error if the device is not turned on.
func (d *Device) ReadTemperature() (temperature int32, err error) {
err = d.waitForOneShot(0x01)
if err != nil {
return
}
// read data and calibrate
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG+1, data[1:])
tValue := readInt(data[1], data[0])
tValueCalib := float32(tValue)*d.temperatureSlope + d.temperatureZero
return int32(tValueCalib * 1000), nil
}
// Resolution sets the HTS221's resolution mode.
// The higher resolutions are more accurate but comsume more power (see datasheet).
// The number of averaged samples will be (h + 2) ^ 2, (t + 1) ^ 2
//
func (d *Device) Resolution(h uint8, t uint8) {
if h > 7 {
h = 3 // default
}
if t > 7 {
t = 3 // default
}
d.bus.WriteRegister(d.Address, HTS221_AV_CONF_REG, []byte{h<<3 | t})
}
// private functions
// read factory calibration data
func (d *Device) calibration() {
h0rH, h1rH := []byte{0}, []byte{0}
t0degC, t1degC := []byte{0}, []byte{0}
t1t0msb := []byte{0}
h0t0Out, h1t0Out := []byte{0, 0}, []byte{0, 0}
t0Out, t1Out := []byte{0, 0}, []byte{0, 0}
d.bus.ReadRegister(d.Address, HTS221_H0_rH_x2_REG, h0rH)
d.bus.ReadRegister(d.Address, HTS221_H1_rH_x2_REG, h1rH)
d.bus.ReadRegister(d.Address, HTS221_T0_degC_x8_REG, t0degC)
d.bus.ReadRegister(d.Address, HTS221_T1_degC_x8_REG, t1degC)
d.bus.ReadRegister(d.Address, HTS221_T1_T0_MSB_REG, t1t0msb)
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG, h0t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG+1, h0t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG, h1t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG+1, h1t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG, t0Out[:1])
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG+1, t0Out[1:])
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG, t1Out[:1])
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG+1, t1Out[1:])
h0rH_v := float32(h0rH[0]) / 2.0
h1rH_v := float32(h1rH[0]) / 2.0
t0degC_v := float32(readUint(t1t0msb[0]&0x03, t0degC[0])) / 8.0
t1degC_v := float32(readUint(t1t0msb[0]&0x0C>>2, t1degC[0])) / 8.0
h0t0Out_v := float32(readInt(h0t0Out[1], h0t0Out[0]))
h1t0Out_v := float32(readInt(h1t0Out[1], h1t0Out[0]))
t0Out_v := float32(readInt(t0Out[1], t0Out[0]))
t1Out_v := float32(readInt(t1Out[1], t1Out[0]))
d.humiditySlope = (h1rH_v - h0rH_v) / (h1t0Out_v - h0t0Out_v)
d.humidityZero = h0rH_v - d.humiditySlope*h0t0Out_v
d.temperatureSlope = (t1degC_v - t0degC_v) / (t1Out_v - t0Out_v)
d.temperatureZero = t0degC_v - d.temperatureSlope*t0Out_v
}
// wait and trigger one shot in block update
func (d *Device) waitForOneShot(filter uint8) error {
data := []byte{0}
// check if the device is on
d.bus.ReadRegister(d.Address, HTS221_CTRL1_REG, data)
if data[0]&0x80 == 0 {
return errors.New("device is off, unable to query")
}
// wait until one shot (one conversion) is ready to go
data[0] = 1
for {
d.bus.ReadRegister(d.Address, HTS221_CTRL2_REG, data)
if data[0]&0x01 == 0 {
break
}
}
// trigger one shot
d.bus.WriteRegister(d.Address, HTS221_CTRL2_REG, []byte{0x01})
// wait until conversion completed
data[0] = 0
for {
d.bus.ReadRegister(d.Address, HTS221_STATUS_REG, data)
if data[0]&filter == filter {
break
}
}
return nil
}
func readUint(msb byte, lsb byte) uint16 {
return uint16(msb)<<8 | uint16(lsb)
}
func readInt(msb byte, lsb byte) int16 {
return int16(uint16(msb)<<8 | uint16(lsb))
}
+14
View File
@@ -0,0 +1,14 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package hts221
import "tinygo.org/x/drivers"
// New creates a new HTS221 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{bus: bus, Address: HTS221_ADDRESS}
}
+29
View File
@@ -0,0 +1,29 @@
//go:build nano_33_ble
// +build nano_33_ble
package hts221
import (
"machine"
"time"
"tinygo.org/x/drivers"
)
// New creates a new HTS221 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
// and wait a moment.
ENV := machine.P0_22
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
ENV.High()
R := machine.P1_00
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
R.High()
time.Sleep(time.Millisecond * 10)
return Device{bus: bus, Address: HTS221_ADDRESS}
}
+27
View File
@@ -0,0 +1,27 @@
package hts221
const (
// I2C address
HTS221_ADDRESS = 0x5F
// control/status registers
HTS221_WHO_AM_I_REG = 0x0F
HTS221_AV_CONF_REG = 0x10
HTS221_CTRL1_REG = 0x20
HTS221_CTRL2_REG = 0x21
HTS221_STATUS_REG = 0x27
HTS221_HUMID_OUT_REG = 0x28
HTS221_TEMP_OUT_REG = 0x2A
// calibration registers
HTS221_H0_rH_x2_REG = 0x30
HTS221_H1_rH_x2_REG = 0x31
HTS221_T0_degC_x8_REG = 0x32
HTS221_T1_degC_x8_REG = 0x33
HTS221_T1_T0_MSB_REG = 0x35
HTS221_H0_T0_OUT_REG = 0x36
HTS221_H1_T0_OUT_REG = 0x3A
HTS221_T0_OUT_REG = 0x3C
HTS221_T1_OUT_REG = 0x3E
)
+280
View File
@@ -0,0 +1,280 @@
package i2csoft
import (
"errors"
"machine"
)
// I2C is an I2C implementation by Software. Since it is implemented by
// software, it can be used with microcontrollers that do not have I2C
// function. This is not efficient but works around broken or missing drivers.
type I2C struct {
scl machine.Pin
sda machine.Pin
nack bool
baudrate uint32
}
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
SCL machine.Pin
SDA machine.Pin
}
var (
errSI2CAckExpected = errors.New("I2C error: expected ACK not NACK")
)
// New returns the i2csoft driver. For the arguments, specify the pins to be
// used as SCL and SDA. As I2C is implemented in software, any GPIO pin can be
// specified.
func New(sclPin, sdaPin machine.Pin) *I2C {
return &I2C{
scl: sclPin,
sda: sdaPin,
baudrate: 100e3,
}
}
// Configure is intended to setup the I2C interface.
func (i2c *I2C) Configure(config I2CConfig) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency != 0 {
i2c.SetBaudRate(config.Frequency)
}
// This exists for compatibility with machine.I2CConfig. SCL and SDA must
// be set at the same time. Because Pin(0) is sometimes set, it is not
// checked for 0.
if config.SCL != config.SDA {
i2c.scl = config.SCL
i2c.sda = config.SDA
}
// enable pins
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.sda.High()
i2c.scl.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.scl.High()
return nil
}
// SetBaudRate sets the communication speed for the I2C.
func (i2c *I2C) SetBaudRate(br uint32) {
// At this time, the value of i2c.baudrate is ignored because it is fixed
// at 100 kHz. SetBaudrate() is exist for compatibility with machine.I2C.
i2c.baudrate = br
}
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
i2c.nack = false
if len(w) != 0 {
// send start/address for write
i2c.sendAddress(addr, true)
// wait until transmission complete
// ACK received (0: ACK, 1: NACK)
if i2c.nack {
i2c.signalStop()
return errSI2CAckExpected
}
// write data
for _, b := range w {
i2c.writeByte(b)
}
i2c.signalStop()
}
if len(r) != 0 {
// send start/address for read
i2c.sendAddress(addr, false)
// wait transmission complete
// ACK received (0: ACK, 1: NACK)
if i2c.nack {
i2c.signalStop()
return errSI2CAckExpected
}
// read first byte
r[0] = i2c.readByte()
for i := 1; i < len(r); i++ {
// Send an ACK
i2c.signalRead()
// Read data and send the ACK
r[i] = i2c.readByte()
}
// Send NACK to end transmission
i2c.sendNack()
i2c.signalStop()
}
return nil
}
// writeByte writes a single byte to the I2C bus.
func (i2c *I2C) writeByte(data byte) {
// Send data byte
i2c.scl.Low()
i2c.sda.High()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.wait()
for i := 0; i < 8; i++ {
i2c.scl.Low()
if ((data >> (7 - i)) & 1) == 1 {
i2c.sda.High()
} else {
i2c.sda.Low()
}
i2c.wait()
i2c.wait()
i2c.scl.High()
i2c.wait()
i2c.wait()
}
i2c.scl.Low()
i2c.wait()
i2c.wait()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
i2c.scl.High()
i2c.wait()
i2c.nack = i2c.sda.Get()
i2c.wait()
// wait until transmission successful
}
// sendAddress sends the address and start signal
func (i2c *I2C) sendAddress(address uint16, write bool) {
data := (address << 1)
if !write {
data |= 1 // set read flag
}
i2c.scl.High()
i2c.sda.Low()
i2c.wait()
i2c.wait()
for i := 0; i < 8; i++ {
i2c.scl.Low()
if ((data >> (7 - i)) & 1) == 1 {
i2c.sda.High()
} else {
i2c.sda.Low()
}
i2c.wait()
i2c.wait()
i2c.scl.High()
i2c.wait()
i2c.wait()
}
i2c.scl.Low()
i2c.wait()
i2c.wait()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
i2c.scl.High()
i2c.wait()
i2c.nack = i2c.sda.Get()
i2c.wait()
// wait until bus ready
}
func (i2c *I2C) signalStop() {
i2c.scl.Low()
i2c.sda.Low()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.wait()
i2c.wait()
i2c.scl.High()
i2c.wait()
i2c.wait()
i2c.sda.High()
i2c.wait()
i2c.wait()
}
func (i2c *I2C) signalRead() {
i2c.wait()
i2c.wait()
i2c.scl.Low()
i2c.sda.Low()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.wait()
i2c.wait()
i2c.scl.High()
i2c.wait()
i2c.wait()
}
func (i2c *I2C) readByte() byte {
var data byte
for i := 0; i < 8; i++ {
i2c.scl.Low()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
i2c.wait()
i2c.wait()
i2c.scl.High()
if i2c.sda.Get() {
data |= 1 << (7 - i)
}
i2c.wait()
i2c.wait()
}
return data
}
func (i2c *I2C) sendNack() {
i2c.wait()
i2c.wait()
i2c.scl.Low()
i2c.sda.High()
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
i2c.wait()
i2c.wait()
i2c.scl.High()
i2c.wait()
i2c.wait()
}
// WriteRegister transmits first the register and then the data to the
// peripheral device.
//
// Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily write to such registers. Also, it only works for
// devices with 7-bit addresses, which is the vast majority.
func (i2c *I2C) WriteRegister(address uint8, register uint8, data []byte) error {
buf := make([]uint8, len(data)+1)
buf[0] = register
copy(buf[1:], data)
return i2c.Tx(uint16(address), buf, nil)
}
// ReadRegister transmits the register, restarts the connection as a read
// operation, and reads the response.
//
// Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily read such registers. Also, it only works for devices
// with 7-bit addresses, which is the vast majority.
func (i2c *I2C) ReadRegister(address uint8, register uint8, data []byte) error {
return i2c.Tx(uint16(address), []byte{register}, data)
}
+17
View File
@@ -0,0 +1,17 @@
//go:build atsamd51 || atsame5x
// +build atsamd51 atsame5x
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval. It is set to
// about 100 kHz.
func (i2c *I2C) wait() {
wait := 20
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+17
View File
@@ -0,0 +1,17 @@
//go:build esp32
// +build esp32
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval. It is set to
// about 100 kHz.
func (i2c *I2C) wait() {
wait := 60
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+17
View File
@@ -0,0 +1,17 @@
//go:build nrf52840
// +build nrf52840
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval. It is set to
// about 100 kHz.
func (i2c *I2C) wait() {
wait := 26
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+16
View File
@@ -0,0 +1,16 @@
//go:build !esp32 && !atsamd51 && !atsame5x && !stm32f4 && !rp2040 && !nrf52840
// +build !esp32,!atsamd51,!atsame5x,!stm32f4,!rp2040,!nrf52840
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval.
func (i2c *I2C) wait() {
wait := 20
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+17
View File
@@ -0,0 +1,17 @@
//go:build rp2040
// +build rp2040
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval. It is set to
// about 100 kHz.
func (i2c *I2C) wait() {
wait := 50
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+17
View File
@@ -0,0 +1,17 @@
//go:build stm32f4
// +build stm32f4
package i2csoft
import (
"device"
)
// wait waits for half the time of the SCL operation interval. It is set to
// about 100 kHz.
func (i2c *I2C) wait() {
wait := 77
for i := 0; i < wait; i++ {
device.Asm(`nop`)
}
}
+73
View File
@@ -0,0 +1,73 @@
// Package lps22hb implements a driver for LPS22HB, a MEMS nano pressure sensor.
//
// Datasheet: https://www.st.com/resource/en/datasheet/dm00140895.pdf
//
package lps22hb
import (
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a HTS221 device.
type Device struct {
bus drivers.I2C
Address uint8
}
// Connected returns whether LPS22HB has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, LPS22HB_WHO_AM_I_REG, data)
return data[0] == 0xB1
}
// Configure sets up the LPS22HB device for communication.
func (d *Device) Configure() {
// set to block update mode
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
}
// ReadPressure returns the pressure in milli pascals (mPa).
func (d *Device) ReadPressure() (pressure int32, err error) {
d.waitForOneShot()
// read data
data := []byte{0, 0, 0}
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+1, data[1:2])
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+2, data[2:])
pValue := float32(uint32(data[2])<<16|uint32(data[1])<<8|uint32(data[0])) / 4096.0
return int32(pValue * 1000), nil
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *Device) ReadTemperature() (temperature int32, err error) {
d.waitForOneShot()
// read data
data := []byte{0, 0}
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG, data[:1])
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG+1, data[1:])
tValue := float32(int16(uint16(data[1])<<8|uint16(data[0]))) / 100.0
return int32(tValue * 1000), nil
}
// private functions
// wait and trigger one shot in block update
func (d *Device) waitForOneShot() {
// trigger one shot
d.bus.WriteRegister(d.Address, LPS22HB_CTRL2_REG, []byte{0x01})
// wait until one shot is cleared
data := []byte{1}
for {
d.bus.ReadRegister(d.Address, LPS22HB_CTRL2_REG, data)
if data[0]&0x01 == 0 {
break
}
}
}
+14
View File
@@ -0,0 +1,14 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package lps22hb
import "tinygo.org/x/drivers"
// New creates a new LPS22HB connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{bus: bus, Address: LPS22HB_ADDRESS}
}
+29
View File
@@ -0,0 +1,29 @@
//go:build nano_33_ble
// +build nano_33_ble
package lps22hb
import (
"machine"
"time"
"tinygo.org/x/drivers"
)
// New creates a new LPS22HB connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
// and wait a moment.
ENV := machine.P0_22
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
ENV.High()
R := machine.P1_00
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
R.High()
time.Sleep(time.Millisecond * 10)
return Device{bus: bus, Address: LPS22HB_ADDRESS}
}
+15
View File
@@ -0,0 +1,15 @@
package lps22hb
const (
// I2C address
LPS22HB_ADDRESS = 0x5C
// control/status registers
LPS22HB_WHO_AM_I_REG = 0x0F
LPS22HB_CTRL1_REG = 0x10
LPS22HB_CTRL2_REG = 0x11
LPS22HB_STATUS_REG = 0x27
LPS22HB_PRESS_OUT_REG = 0x28
LPS22HB_TEMP_OUT_REG = 0x2B
)
+227
View File
@@ -0,0 +1,227 @@
// LSM9DS1, 9 axis Inertial Measurement Unit (IMU)
//
// Datasheet: https://www.st.com/resource/en/datasheet/lsm6ds3.pdf
//
package lsm9ds1 // import "tinygo.org/x/drivers/lsm9ds1"
import (
"errors"
"tinygo.org/x/drivers"
)
type AccelRange uint8
type AccelSampleRate uint8
type AccelBandwidth uint8
type GyroRange uint8
type GyroSampleRate uint8
type MagRange uint8
type MagSampleRate uint8
// Device wraps connection to a LSM9DS1 device.
type Device struct {
bus drivers.I2C
AccelAddress uint8
MagAddress uint8
accelMultiplier int32
gyroMultiplier int32
magMultiplier int32
dataBufferSix []uint8
dataBufferTwo []uint8
}
// Configuration for LSM9DS1 device.
type Configuration struct {
AccelRange AccelRange
AccelSampleRate AccelSampleRate
AccelBandWidth AccelBandwidth
GyroRange GyroRange
GyroSampleRate GyroSampleRate
MagRange MagRange
MagSampleRate MagSampleRate
}
var errNotConnected = errors.New("lsm9ds1: failed to communicate with either acel/gyro or magnet sensor")
// New creates a new LSM9DS1 connection. The I2C bus must already be configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) *Device {
return &Device{
bus: bus,
AccelAddress: ACCEL_ADDRESS,
MagAddress: MAG_ADDRESS,
dataBufferSix: make([]uint8, 6),
dataBufferTwo: make([]uint8, 2),
}
}
// Connected returns whether both sensor on LSM9DS1 has been found.
// It does two "who am I" requests and checks the responses.
// In a rare case of an I2C bus issue, it can also return an error.
// Case of boolean false and error nil means I2C is up,
// but "who am I" responses have unexpected values.
func (d *Device) Connected() (connected bool, err error) {
data1, data2 := []byte{0}, []byte{0}
err = d.bus.ReadRegister(d.AccelAddress, WHO_AM_I, data1)
if err != nil {
return false, err
}
err = d.bus.ReadRegister(d.MagAddress, WHO_AM_I_M, data2)
if err != nil {
return false, err
}
return data1[0] == 0x68 && data2[0] == 0x3D, nil
}
// ReadAcceleration reads the current acceleration from the device and returns
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_XL, d.dataBufferSix)
if err != nil {
return
}
x = int32(int16((uint16(d.dataBufferSix[1])<<8)|uint16(d.dataBufferSix[0]))) * d.accelMultiplier
y = int32(int16((uint16(d.dataBufferSix[3])<<8)|uint16(d.dataBufferSix[2]))) * d.accelMultiplier
z = int32(int16((uint16(d.dataBufferSix[5])<<8)|uint16(d.dataBufferSix[4]))) * d.accelMultiplier
return
}
// ReadRotation reads the current rotation from the device and returns it in
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_G, d.dataBufferSix)
if err != nil {
return
}
x = int32(int16((uint16(d.dataBufferSix[1])<<8)|uint16(d.dataBufferSix[0]))) * d.gyroMultiplier
y = int32(int16((uint16(d.dataBufferSix[3])<<8)|uint16(d.dataBufferSix[2]))) * d.gyroMultiplier
z = int32(int16((uint16(d.dataBufferSix[5])<<8)|uint16(d.dataBufferSix[4]))) * d.gyroMultiplier
return
}
// ReadMagneticField reads the current magnetic field from the device and returns
// it in nT (nanotesla). 1 G (gauss) = 100_000 nT (nanotesla).
func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
err = d.bus.ReadRegister(uint8(d.MagAddress), OUT_X_L_M, d.dataBufferSix)
if err != nil {
return
}
x = int32(int16((int16(d.dataBufferSix[1])<<8)|int16(d.dataBufferSix[0]))) * d.magMultiplier
y = int32(int16((int16(d.dataBufferSix[3])<<8)|int16(d.dataBufferSix[2]))) * d.magMultiplier
z = int32(int16((int16(d.dataBufferSix[5])<<8)|int16(d.dataBufferSix[4]))) * d.magMultiplier
return
}
// ReadTemperature returns the temperature in Celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_L, d.dataBufferTwo)
if err != nil {
return
}
// From "Table 5. Temperature sensor characteristics"
// temp = value/16 + 25
t = 25000 + (int32(int16((int16(d.dataBufferTwo[1])<<8)|int16(d.dataBufferTwo[0])))*125)/2
return
}
// --- end of public methods --------------------------------------------------
// doConfigure is called by public Configure methods after all
// necessary board-specific initialisations are taken care of
func (d *Device) doConfigure(cfg Configuration) (err error) {
// Verify unit communication
if con, err := d.Connected(); !con || err != nil {
return errNotConnected
}
// Multipliers come from "Table 3. Sensor characteristics" of the datasheet * 1000
switch cfg.AccelRange {
case ACCEL_2G:
d.accelMultiplier = 61
case ACCEL_4G:
d.accelMultiplier = 122
case ACCEL_8G:
d.accelMultiplier = 244
case ACCEL_16G:
d.accelMultiplier = 732
}
switch cfg.GyroRange {
case GYRO_250DPS:
d.gyroMultiplier = 8750
case GYRO_500DPS:
d.gyroMultiplier = 17500
case GYRO_2000DPS:
d.gyroMultiplier = 70000
}
switch cfg.MagRange {
case MAG_4G:
d.magMultiplier = 14
case MAG_8G:
d.magMultiplier = 29
case MAG_12G:
d.magMultiplier = 43
case MAG_16G:
d.magMultiplier = 58
}
data := make([]byte, 1)
// Configure accelerometer
// Sample rate & measurement range
data[0] = uint8(cfg.AccelSampleRate)<<5 | uint8(cfg.AccelRange)<<3
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG6_XL, data)
if err != nil {
return
}
// Configure gyroscope
// Sample rate & measurement range
data[0] = uint8(cfg.GyroSampleRate)<<5 | uint8(cfg.GyroRange)<<3
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG1_G, data)
if err != nil {
return
}
// Configure magnetometer
// Temperature compensation enabled
// High-performance mode XY axis
// Sample rate
data[0] = 0b10000000 | 0b01000000 | uint8(cfg.MagSampleRate)<<2
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG1_M, data)
if err != nil {
return
}
// Measurement range
data[0] = uint8(cfg.MagRange) << 5
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG2_M, data)
if err != nil {
return
}
// Continuous-conversion mode
// https://electronics.stackexchange.com/questions/237397/continuous-conversion-vs-single-conversion-mode
data[0] = 0b00000000
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG3_M, data)
if err != nil {
return
}
// High-performance mode Z axis
data[0] = 0b00001000
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG4_M, data)
if err != nil {
return
}
return nil
}
+9
View File
@@ -0,0 +1,9 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package lsm9ds1
// Configure sets up the device for communication.
func (d *Device) Configure(cfg Configuration) error {
return d.doConfigure(cfg)
}
+25
View File
@@ -0,0 +1,25 @@
//go:build nano_33_ble
// +build nano_33_ble
// Nano 33 BLE [Sense] has LSM9DS1 unit on-board.
// This custom Configure function powers unit up
// and enables I2C, so unit can can be accessed.
package lsm9ds1
import (
"machine"
"time"
)
// Configure sets up the device for communication.
func (d *Device) Configure(cfg Configuration) error {
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
machine.LSM_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.LSM_PWR.High()
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.I2C_PULLUP.High()
// Wait a moment
time.Sleep(10 * time.Millisecond)
// Common initialisation code
return d.doConfigure(cfg)
}
+102
View File
@@ -0,0 +1,102 @@
package lsm9ds1
// Constants/addresses used for I2C.
const (
// Constants/addresses used for I2C.
ACCEL_ADDRESS = 0x6B
MAG_ADDRESS = 0x1E
// Table 21. Accelerometer and gyroscope register address map
WHO_AM_I = 0x0F // value 0x68
CTRL_REG1_G = 0x10
OUT_X_L_G = 0x18
OUT_X_H_G = 0x19
OUT_Y_L_G = 0x1A
OUT_Y_H_G = 0x1B
OUT_Z_L_G = 0x1C
OUT_Z_H_G = 0x1D
OUT_TEMP_L = 0x15
OUT_TEMP_H = 0x16
CTRL_REG6_XL = 0x20
STATUS_REG = 0x27
OUT_X_L_XL = 0x28
OUT_X_H_XL = 0x29
OUT_Y_L_XL = 0x2A
OUT_Y_H_XL = 0x2B
OUT_Z_L_XL = 0x2C
OUT_Z_H_XL = 0x2D
// Table 22. Magnetic sensor register address map
OFFSET_X_REG_L_M = 0x05
OFFSET_X_REG_H_M = 0x06
OFFSET_Y_REG_L_M = 0x07
OFFSET_Y_REG_H_M = 0x08
OFFSET_Z_REG_L_M = 0x09
OFFSET_Z_REG_H_M = 0x0A
WHO_AM_I_M = 0x0F // value 0x3D
CTRL_REG1_M = 0x20 // TEMP_COMP OM1 OM0 DO2 DO1 DO0 FAST_ODR ST
CTRL_REG2_M = 0x21 // 0 FS1 FS0 0 REBOOT SOFT_RST 0 0
CTRL_REG3_M = 0x22 // 0 LP 0 0 SIM MD1 MD0
CTRL_REG4_M = 0x23 // 0 0 0 0 OMZ1 OMZ0 BLE 0
STATUS_REG_M = 0x27
OUT_X_L_M = 0x28
OUT_X_H_M = 0x29
OUT_Y_L_M = 0x2A
OUT_Y_H_M = 0x2B
OUT_Z_L_M = 0x2C
OUT_Z_H_M = 0x2D
// Table 67. CTRL_REG6_XL register description
ACCEL_2G AccelRange = 0b00
ACCEL_4G AccelRange = 0b10
ACCEL_8G AccelRange = 0b11
ACCEL_16G AccelRange = 0b01
// Table 68. ODR register setting (accelerometer only mode)
ACCEL_SR_OFF AccelSampleRate = 0b000
ACCEL_SR_10 AccelSampleRate = 0b001
ACCEL_SR_50 AccelSampleRate = 0b010
ACCEL_SR_119 AccelSampleRate = 0b011
ACCEL_SR_238 AccelSampleRate = 0b100
ACCEL_SR_476 AccelSampleRate = 0b101
ACCEL_SR_952 AccelSampleRate = 0b110
// Table 67. CTRL_REG6_XL register description
ACCEL_BW_50 AccelBandwidth = 0b11
ACCEL_BW_105 AccelBandwidth = 0b10
ACCEL_BW_211 AccelBandwidth = 0b01
ACCEL_BW_408 AccelBandwidth = 0b00
// Table 45. CTRL_REG1_G register description
GYRO_250DPS GyroRange = 0b00
GYRO_500DPS GyroRange = 0b01
GYRO_2000DPS GyroRange = 0b11
// Table 9. Gyroscope operating modes
// Table 46. ODR and BW configuration setting (after LPF1)
GYRO_SR_OFF GyroSampleRate = 0b000
GYRO_SR_15 GyroSampleRate = 0b001
GYRO_SR_60 GyroSampleRate = 0b010
GYRO_SR_119 GyroSampleRate = 0b011
GYRO_SR_238 GyroSampleRate = 0b100
GYRO_SR_476 GyroSampleRate = 0b101
GYRO_SR_952 GyroSampleRate = 0b110
// Table 114. Full-scale selection
MAG_4G MagRange = 0b00
MAG_8G MagRange = 0b01
MAG_12G MagRange = 0b10
MAG_16G MagRange = 0b11
// Table 111. Output data rate configuration
MAG_SR_06 MagSampleRate = 0b000
MAG_SR_1 MagSampleRate = 0b001
MAG_SR_2 MagSampleRate = 0b010
MAG_SR_5 MagSampleRate = 0b011
MAG_SR_10 MagSampleRate = 0b100
MAG_SR_20 MagSampleRate = 0b101
MAG_SR_40 MagSampleRate = 0b110
MAG_SR_80 MagSampleRate = 0b111
)
+1 -1
View File
@@ -83,7 +83,7 @@ func (p ADCPin) Get() uint16 {
p.d.bus.Tx(p.d.tx, p.d.rx)
// scale result to 16bit value like other ADCs
result := uint16((p.d.rx[1]&0x3))<<8 + uint16(p.d.rx[2])<<6
result := uint16((p.d.rx[1]&0x3))<<(8+6) + uint16(p.d.rx[2])<<6
p.d.cs.High()
return result
+1 -1
View File
@@ -186,7 +186,7 @@ func (c *TCPSerialConn) LocalAddr() Addr {
// RemoteAddr returns the remote network address.
func (c *TCPSerialConn) RemoteAddr() Addr {
return c.laddr.opAddr()
return c.raddr.opAddr()
}
func (c *TCPSerialConn) opConn() Conn {
+1 -1
View File
@@ -2,7 +2,7 @@
// series by Sensirion.
//
// Datasheet:
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf
//
package sht3x // import "tinygo.org/x/drivers/sht3x"
+1 -1
View File
@@ -2,4 +2,4 @@ package drivers
// Version returns a user-readable string showing the version of the drivers package for support purposes.
// Update this value before release of new version of software.
const Version = "0.17.1"
const Version = "0.18.0"
+65
View File
@@ -0,0 +1,65 @@
package wifinina
import "errors"
// Mimics machine package's pin control
//
// NB! These are NINA chip pins, not main unit pins.
//
// Digital pin values and modes taken from
// https://github.com/arduino/nina-fw/blob/master/arduino/cores/esp32/wiring_digital.h
type Pin uint8
const (
PinLow uint8 = iota
PinHigh
)
type PinMode uint8
const (
PinInput PinMode = iota
PinOutput
PinInputPullup
)
type PinConfig struct {
Mode PinMode
}
var (
ErrPinNoDevice = errors.New("wifinina pin: device not set")
)
var pinDevice *Device
func pinUseDevice(d *Device) {
pinDevice = d
}
func (p Pin) Configure(config PinConfig) error {
if pinDevice == nil {
return ErrPinNoDevice
}
return pinDevice.PinMode(uint8(p), uint8(config.Mode))
}
func (p Pin) Set(high bool) error {
if pinDevice == nil {
return ErrPinNoDevice
}
value := PinLow
if high {
value = PinHigh
}
return pinDevice.DigitalWrite(uint8(p), value)
}
func (p Pin) High() error {
return p.Set(true)
}
func (p Pin) Low() error {
return p.Set(false)
}
+38
View File
@@ -297,6 +297,7 @@ func New(bus drivers.SPI, csPin, ackPin, gpio0Pin, resetPin machine.Pin) *Device
func (d *Device) Configure() {
net.UseDriver(d.NewDriver())
pinUseDevice(d)
d.CS.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.ACK.Configure(machine.PinConfig{Mode: machine.PinInput})
@@ -689,6 +690,23 @@ func (d *Device) StartScanNetworks() (uint8, error) {
return d.getUint8(d.req0(CmdStartScanNetworks))
}
func (d *Device) PinMode(pin uint8, mode uint8) error {
_, err := d.req2Uint8(CmdSetPinMode, pin, mode)
return err
}
func (d *Device) DigitalWrite(pin uint8, value uint8) error {
_, err := d.req2Uint8(CmdSetDigitalWrite, pin, value)
return err
}
func (d *Device) AnalogWrite(pin uint8, value uint8) error {
_, err := d.req2Uint8(CmdSetAnalogWrite, pin, value)
return err
}
// ------------- End of public device interface ----------------------------
func (d *Device) getString(l uint8, err error) (string, error) {
if err != nil {
return "", err
@@ -773,6 +791,14 @@ func (d *Device) reqUint8(cmd uint8, data uint8) (l uint8, err error) {
return d.waitRspCmd1(cmd)
}
// req2Uint8 sends a command to the device with two uint8 parameters
func (d *Device) req2Uint8(cmd, p1, p2 uint8) (l uint8, err error) {
if err := d.sendCmdPadded2(cmd, p1, p2); err != nil {
return 0, err
}
return d.waitRspCmd1(cmd)
}
// reqStr sends a command to the device with a single string parameter
func (d *Device) reqStr(cmd uint8, p1 string) (uint8, error) {
if err := d.sendCmdStr(cmd, p1); err != nil {
@@ -834,6 +860,18 @@ func (d *Device) sendCmdPadded1(cmd uint8, data uint8) error {
return nil
}
func (d *Device) sendCmdPadded2(cmd, data1, data2 uint8) error {
defer d.spiChipDeselect()
if err := d.waitForChipSelect(); err != nil {
return err
}
l := d.sendCmd(cmd, 1)
l += d.sendParam8(data1, false)
l += d.sendParam8(data2, true)
d.SPI.Transfer(dummyData)
return nil
}
func (d *Device) sendCmdStr(cmd uint8, p1 string) (err error) {
defer d.spiChipDeselect()
if err := d.waitForChipSelect(); err != nil {
+113 -37
View File
@@ -5,9 +5,11 @@ package main
import (
"bytes"
"flag"
"fmt"
"math"
"os"
"strconv"
"strings"
)
@@ -34,10 +36,77 @@ import (
// The timings deviate a little bit from the code here, but so far the timings
// from wp.josh.com seem to be fine for the ws2812.
// Clock frequencies to support, in MHz.
var clockFrequencies = []int{16, 48, 64, 120, 168}
// Architecture implementation. Describes the template and the timings of the
// blocks of instructions so that most code can remain architecture-independent.
type architectureImpl struct {
buildTag string
minBaseCyclesT0H int
maxBaseCyclesT0H int
minBaseCyclesT1H int
maxBaseCyclesT1H int
minBaseCyclesTLD int
valueTemplate string // template for how to pass the 'c' byte to assembly
template string // assembly template
}
func writeImplementation(f *os.File, megahertz int) error {
var architectures = map[string]architectureImpl{
"cortexm": {
// Assume that a branch is 1 to 3 cycles, no matter whether it's taken
// or not. This is a rather conservative estimate, for Cortex-M+ for
// example the instruction cycles are precisely known.
buildTag: "cortexm",
minBaseCyclesT0H: 1 + 1 + 2, // shift + branch (not taken) + store
maxBaseCyclesT0H: 1 + 3 + 2, // shift + branch (not taken) + store
minBaseCyclesT1H: 1 + 1 + 2, // shift + branch (taken) + store
maxBaseCyclesT1H: 1 + 3 + 2, // shift + branch (taken) + store
minBaseCyclesTLD: 1 + 1 + 2, // subtraction + branch + store (in next cycle)
valueTemplate: "uint32(c) << 24",
template: `
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
@DELAY1
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
@DELAY2
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
@DELAY3
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`,
},
"tinygoriscv": {
// Largely based on the SiFive FE310 CPU:
// - stores are 1 cycle
// - branches are 1 or 3 cycles, depending on branch prediction
// - ALU operations are 1 cycle (as on most CPUs)
// Hopefully this generalizes to other chips.
buildTag: "tinygo.riscv32",
minBaseCyclesT0H: 1 + 1 + 1, // shift + branch (not taken) + store
maxBaseCyclesT0H: 1 + 3 + 1, // shift + branch (not taken) + store
minBaseCyclesT1H: 1 + 1 + 1, // shift + branch (taken) + store
maxBaseCyclesT1H: 1 + 3 + 1, // shift + branch (taken) + store
minBaseCyclesTLD: 1 + 1 + 1, // subtraction + branch + store (in next cycle)
valueTemplate: "uint32(c) << 23",
template: `
1: // send_bit
sw {maskSet}, {portSet} // [1] T0H and T0L start here
@DELAY1
slli {value}, {value}, 1 // [1] shift value left by 1
bltz {value}, 2f // [1/3] skip_store
sw {maskClear}, {portClear} // [1] T0H -> T0L transition
2: // skip_store
@DELAY2
sw {maskClear}, {portClear} // [1] T1H -> T1L transition
@DELAY3
addi {i}, {i}, -1 // [1]
bnez {i}, 1b // [1/3] send_bit
`,
},
}
func writeImplementation(f *os.File, arch string, megahertz int) error {
cycleTimeNS := 1 / float64(megahertz)
// These timings are taken from the table "Updated simplified timing
// constraints for NeoPixel strings" at:
@@ -72,7 +141,7 @@ func writeImplementation(f *os.File, megahertz int) error {
maxCyclesT1H := int(math.Floor(5.500 / cycleTimeNS))
minCyclesTLD := int(math.Ceil(1.150 / cycleTimeNS))
// Assembly template:
// The assembly template looks something like this:
// 1: @ send_bit
// str {maskSet}, {portSet} @ [2] T0H and T0L start here
// ...delay 1
@@ -87,29 +156,31 @@ func writeImplementation(f *os.File, megahertz int) error {
// bne.n 1b @ [1/3] send_bit
//
// We need to calculate the number of nop instructions in the three delays.
archImpl, ok := architectures[arch]
if !ok {
return fmt.Errorf("unknown architecture: %s", arch)
}
// Determine number of nops for delay1. This is primarily based on the T0H
// delay, which is relatively short (<500ns).
minBaseCyclesT0H := 1 + 1 + 2 // shift + branch + store
maxBaseCyclesT0H := 1 + 3 + 2 // shift + branch + store
delay1 := minCyclesT0H - minBaseCyclesT0H
delay1 := minCyclesT0H - archImpl.minBaseCyclesT0H
if delay1 < 0 {
// The minCyclesT0H constraint could not be satisfied. Don't insert
// nops, in the hope that it isn't too long.
delay1 = 0
}
if delay1+maxBaseCyclesT0H > maxCyclesT0H {
if delay1+archImpl.maxBaseCyclesT0H > maxCyclesT0H {
return fmt.Errorf("MCU appears to be too slow to satisfy minimum requirements for the T0H signal")
}
actualMinCyclesT0H := minBaseCyclesT0H + delay1
actualMaxCyclesT0H := maxBaseCyclesT0H + delay1
actualMinCyclesT0H := archImpl.minBaseCyclesT0H + delay1
actualMaxCyclesT0H := archImpl.maxBaseCyclesT0H + delay1
actualMinNanosecondsT0H := float64(actualMinCyclesT0H) / float64(megahertz) * 1000
actualMaxNanosecondsT0H := float64(actualMaxCyclesT0H) / float64(megahertz) * 1000
// Determine number of nops for delay2. This is delay1 plus some extra time
// so that the pulse is long enough for T1H.
minBaseCyclesT1H := delay1 + 1 + 1 + 2 // delay1 + shift + branch + store
maxBaseCyclesT1H := delay1 + 1 + 3 + 2 // delay1 + shift + branch + store
minBaseCyclesT1H := delay1 + archImpl.minBaseCyclesT1H // delay1 + asssembly cycles
maxBaseCyclesT1H := delay1 + archImpl.maxBaseCyclesT1H // delay1 + asssembly cycles
delay2 := minCyclesT1H - minBaseCyclesT1H
if delay2 < 0 {
delay2 = 0
@@ -125,12 +196,11 @@ func writeImplementation(f *os.File, megahertz int) error {
// Determine number of nops for delay3. This is based on the TLD delay, the
// time between two high pulses.
minBaseCyclesTLD := 1 + 1 + 2 // subtraction + branch + store (in next cycle)
delay3 := minCyclesTLD - minBaseCyclesTLD
delay3 := minCyclesTLD - archImpl.minBaseCyclesTLD
if delay3 < 0 {
delay3 = 0
}
actualMinCyclesTLD := minBaseCyclesTLD + delay3
actualMinCyclesTLD := archImpl.minBaseCyclesTLD + delay3
actualMinNanosecondsTLD := float64(actualMinCyclesTLD) / float64(megahertz) * 1000
// Create the Go function in a buffer. Using a buffer here to be able to
@@ -146,21 +216,13 @@ func writeImplementation(f *os.File, megahertz int) error {
fmt.Fprintf(buf, " // T1H: %2d - %2d cycles or %.1fns - %.1fns\n", actualMinCyclesT1H, actualMaxCyclesT1H, actualMinNanosecondsT1H, actualMaxNanosecondsT1H)
fmt.Fprintf(buf, " // TLD: %2d - cycles or %.1fns -\n", actualMinCyclesTLD, actualMinNanosecondsTLD)
fmt.Fprintf(buf, " mask := interrupt.Disable()\n")
fmt.Fprintf(buf, " value := uint32(c) << 24\n")
fmt.Fprintf(buf, " device.AsmFull(`\n")
fmt.Fprintf(buf, " 1: @ send_bit\n")
fmt.Fprintf(buf, " str {maskSet}, {portSet} @ [2] T0H and T0L start here\n")
buf.WriteString(strings.Repeat(" nop\n", delay1))
fmt.Fprintf(buf, " lsls {value}, #1 @ [1]\n")
fmt.Fprintf(buf, " bcs.n 2f @ [1/3] skip_store\n")
fmt.Fprintf(buf, " str {maskClear}, {portClear} @ [2] T0H -> T0L transition\n")
fmt.Fprintf(buf, " 2: @ skip_store\n")
buf.WriteString(strings.Repeat(" nop\n", delay2))
fmt.Fprintf(buf, " str {maskClear}, {portClear} @ [2] T1H -> T1L transition\n")
buf.WriteString(strings.Repeat(" nop\n", delay3))
fmt.Fprintf(buf, " subs {i}, #1 @ [1]\n")
fmt.Fprintf(buf, " bne.n 1b @ [1/3] send_bit\n")
fmt.Fprintf(buf, " `, map[string]interface{}{")
fmt.Fprintf(buf, " value := %s\n", archImpl.valueTemplate)
asm := archImpl.template
asm = strings.ReplaceAll(asm, " @DELAY1\n", strings.Repeat(" nop\n", delay1))
asm = strings.ReplaceAll(asm, " @DELAY2\n", strings.Repeat(" nop\n", delay2))
asm = strings.ReplaceAll(asm, " @DELAY3\n", strings.Repeat(" nop\n", delay3))
asm = strings.ReplaceAll(asm, "\n", "\n\t")
fmt.Fprintf(buf, " device.AsmFull(`%s`, map[string]interface{}{", asm)
buf.WriteString(`
"value": value,
"i": 8,
@@ -179,19 +241,33 @@ func writeImplementation(f *os.File, megahertz int) error {
}
func main() {
f, err := os.Create("ws2812-asm_cortexm.go")
arch := flag.String("arch", "cortexm", "architecture to output to")
flag.Parse()
// Remaining parameters are all clock frequencies.
var clockFrequencies []int
for _, s := range flag.Args() {
freq, err := strconv.Atoi(s)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot parse frequency:", s)
os.Exit(1)
}
clockFrequencies = append(clockFrequencies, freq)
}
f, err := os.Create("ws2812-asm_" + *arch + ".go")
if err != nil {
fmt.Fprintln(os.Stderr, "could not generate WS2812 assembly code:", err)
os.Exit(1)
}
defer f.Close()
f.WriteString(`//go:build cortexm
// +build cortexm
fmt.Fprintln(f, "//go:build", architectures[*arch].buildTag)
fmt.Fprintln(f, "// +build", architectures[*arch].buildTag)
f.WriteString(`
package ws2812
// Warning: autogenerated file. Instead of modifying this file, change
// gen-ws2812-arm.go and run "go generate".
// gen-ws2812.go and run "go generate".
import (
"device"
@@ -199,9 +275,9 @@ import (
)
`)
for _, megahertz := range clockFrequencies {
err := writeImplementation(f, megahertz)
err := writeImplementation(f, *arch, megahertz)
if err != nil {
fmt.Fprintf(os.Stderr, "could not generate WS2812 assembly code for %dMHz: %s\n", megahertz, err)
fmt.Fprintf(os.Stderr, "could not generate WS2812 assembly code for %s and %dMHz: %s\n", *arch, megahertz, err)
os.Exit(1)
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
package ws2812
// Warning: autogenerated file. Instead of modifying this file, change
// gen-ws2812-arm.go and run "go generate".
// gen-ws2812.go and run "go generate".
import (
"device"
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,7 +1,8 @@
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
package ws2812 // import "tinygo.org/x/drivers/ws2812"
//go:generate go run gen-ws2812-arm.go
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 168
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
import (
"errors"
+20
View File
@@ -0,0 +1,20 @@
//go:build tinygo.riscv32
// +build tinygo.riscv32
package ws2812
import "machine"
// Send a single byte using the WS2812 protocol.
func (d Device) WriteByte(c byte) error {
switch machine.CPUFrequency() {
case 160_000_000: // 160MHz, e.g. esp32c3
d.writeByte160(c)
return nil
case 320_000_000: // 320MHz, e.g. fe310
d.writeByte320(c)
return nil
default:
return errUnknownClockSpeed
}
}