mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-29 12:08:40 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dbff576c9e | |||
| f0a260be66 | |||
| 06e298c514 | |||
| f2f470973d | |||
| 448598cbf8 | |||
| ec98f2dc2c | |||
| 2476cd7bd8 | |||
| 01fed475e1 | |||
| edfdd4e09e | |||
| 5e54f08605 | |||
| 880b958d64 | |||
| 24db8b4e2c | |||
| 6df9247f92 | |||
| 56fb346438 | |||
| 3d279d4d25 | |||
| 4a336f674c | |||
| 2d32995f6a | |||
| 9a98d1be55 | |||
| 02e4548966 | |||
| 45dce188f5 | |||
| b3c0315a09 | |||
| 0ced12683c | |||
| b4eb406a43 | |||
| 10bd48c39d | |||
| ad3ef92cfe | |||
| f7dce6ae22 | |||
| a15f2167cc | |||
| 5d5378a47c | |||
| 3ceb688663 | |||
| 941c1c9057 | |||
| d8c813d515 | |||
| 905fc6fce3 | |||
| 80913d5fe7 | |||
| b6c750ccd1 | |||
| 43899e1330 | |||
| 45c68ef0fc | |||
| 025a66655f | |||
| 121e8147f7 | |||
| b48bc5ac5d | |||
| 0d40c99d1f | |||
| bee7422c3a | |||
| 43099c5d5f | |||
| 0f9b9d873b | |||
| 114e24870e | |||
| b33c84ff78 | |||
| 966210f1b0 |
@@ -1,3 +1,71 @@
|
||||
0.20.0
|
||||
---
|
||||
- **new devices**
|
||||
- irremote: Add basic infra-red driver
|
||||
- IS31FL3731: add driver for IS31FL3731 matrix LED driver (#370)
|
||||
- l3gd20: add gyro driver
|
||||
- SSD1289: Driver for SSD1289 LCD
|
||||
|
||||
- **enhancements**
|
||||
- **ili9341**
|
||||
- add support for atsame5x
|
||||
- added Feather board support to InitDisplay()
|
||||
- avoid heap allocations
|
||||
- **lps22hb**
|
||||
- pin rename, sync with main repo
|
||||
- **lsmXXX**
|
||||
- unified, error handling, memory management
|
||||
- **max7xx**
|
||||
- Add a SetIntensity() function to max7xx driver and example
|
||||
- **vl53l1x**
|
||||
- Add functions for setting 'region of interest'
|
||||
- Fix switch-case semantics
|
||||
- **ws2812**
|
||||
- add support for m5stamp-c3
|
||||
- convert AVR assembly to C inline assembly
|
||||
- support high-MHz ARMv6M chips like the RP2040
|
||||
- write inline assembly using C instead of Go
|
||||
|
||||
- **bugfixes**
|
||||
- **dht**
|
||||
- fix error check in example
|
||||
- fix humidity and temperature extraction for DHT22 (#358)
|
||||
- **esp8266**
|
||||
- fix ConnectToAccessPoint timeout args
|
||||
- **image**
|
||||
- fix interface
|
||||
- **pca9685**
|
||||
- add buffered one shot write
|
||||
- fix on=0 bug
|
||||
- **wifinina**
|
||||
- correct sendParamStr to handle empty strings, such as when connecting to an unsecured access point
|
||||
|
||||
0.19.0
|
||||
---
|
||||
- **new devices**
|
||||
- ft6336: add support for ft6336
|
||||
- pca9685: PCA9685 driver
|
||||
- shtc3: Sensirion SHTC3 Relative Humidity / Temperature i2c sensor
|
||||
- sx126x: Driver for Semtech sx126x radio modules
|
||||
- xpt2046: XPT2046 Touch driver (#350)
|
||||
- **enhancements**
|
||||
- **hd44780i2c**
|
||||
- clean up for go fmt
|
||||
- Needed fixes and update hd44780i2c.go
|
||||
- **ili9341, ili9342**
|
||||
- add support for m5stack
|
||||
- add support for m5stack-core2
|
||||
- **wifi**
|
||||
- modify to use shared net.Adapter interface for all supported wifi devices
|
||||
- wifinina: remove busy wait
|
||||
- **bugfixes**
|
||||
- **hd44780**
|
||||
- fix 4-bit data length flag
|
||||
- Reset data pins to output mode after reading
|
||||
- Nano 33 BLE drivers (#351)
|
||||
- **docs**
|
||||
- examples/wifi: add unified example for tcpclient that compiles for all supported wifi adaptors
|
||||
|
||||
0.18.0
|
||||
---
|
||||
- **new devices**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2021 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
||||
@@ -107,6 +107,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
|
||||
@@ -117,6 +119,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
||||
@@ -155,6 +159,10 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.bin -target=m5stamp-c3 ./examples/ws2812
|
||||
@md5sum ./build/test.bin
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/is31fl3731/main.go
|
||||
@md5sum ./build/test.hex
|
||||
ifneq ($(AVR), 0)
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/ws2812
|
||||
@md5sum ./build/test.hex
|
||||
@@ -187,8 +195,8 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||
@md5sum ./build/test.hex
|
||||
# tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||
# @md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
|
||||
@@ -215,15 +223,28 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
|
||||
@md5sum ./build/test.uf2
|
||||
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/basic/
|
||||
@md5sum ./build/test.elf
|
||||
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/touchpaint/
|
||||
@md5sum ./build/test.elf
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/sx126x/lora_rxtx/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/ssd1289/main.go
|
||||
@md5sum ./build/test.uf2
|
||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/irremote/main.go
|
||||
@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 i2csoft hts221 lps22hb apds9960 axp192
|
||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x keypad4x4 max72xx p1am tone tm1637 \
|
||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 \
|
||||
ft6336 sx126x ssd1289 irremote
|
||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||
|
||||
unit-test:
|
||||
@go test -v $(addprefix ./,$(TESTS))
|
||||
@go test -v $(addprefix ./,$(TESTS))
|
||||
|
||||
test: clean fmt-check unit-test smoke-test
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 74 devices are supported.
|
||||
The following 78 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|----------|-------------|
|
||||
@@ -78,6 +78,7 @@ The following 74 devices are supported.
|
||||
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
||||
| [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI |
|
||||
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
|
||||
| [FT6336 touch controller](https://focuslcds.com/content/FT6236.pdf) | I2C |
|
||||
| [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 |
|
||||
@@ -86,6 +87,8 @@ The following 74 devices are supported.
|
||||
| [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 |
|
||||
| [Infrared remote control](https://en.wikipedia.org/wiki/Consumer_IR) | GPIO |
|
||||
| [IS31FL3731 matrix LED driver](https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf) | I2C |
|
||||
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
|
||||
| [L293x motor driver](https://www.ti.com/lit/ds/symlink/l293d.pdf) | GPIO/PWM |
|
||||
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
|
||||
@@ -114,6 +117,7 @@ The following 74 devices are supported.
|
||||
| [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/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SHTC3 Digital Humidity Sensor (RH/T)](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.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 |
|
||||
@@ -131,6 +135,9 @@ The following 74 devices are supported.
|
||||
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) | SPI |
|
||||
| [Waveshare 4.2" e-paper B/W display](https://www.waveshare.com/w/upload/6/6a/4.2inch-e-paper-specification.pdf) | SPI |
|
||||
| [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO |
|
||||
| [XPT2046 touch controller](http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) | GPIO |
|
||||
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-transceiv-ers/sx1261) | SPI |
|
||||
| [SSD1289 TFT color display](http://aitendo3.sakura.ne.jp/aitendo_data/product_img/lcd/tft2/M032C1289TP/3.2-SSD1289.pdf) | GPIO |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+53
-46
@@ -57,6 +57,14 @@ type enableConfig struct {
|
||||
PON bool
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Connected returns whether APDS-9960 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
@@ -65,52 +73,6 @@ func (d *Device) Connected() bool {
|
||||
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
|
||||
@@ -353,6 +315,51 @@ func (d *Device) ReadGesture() (gesture int32) {
|
||||
|
||||
// private functions
|
||||
|
||||
func (d *Device) configureDevice(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)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) enable(cfg enableConfig) {
|
||||
var gen, pien, aien, wen, pen, aen, pon uint8
|
||||
|
||||
|
||||
@@ -5,10 +5,8 @@ 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}
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
// configure device
|
||||
d.configureDevice(cfg)
|
||||
}
|
||||
|
||||
@@ -6,24 +6,19 @@ 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)
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
// 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)
|
||||
|
||||
// configure device
|
||||
d.configureDevice(cfg)
|
||||
}
|
||||
|
||||
+3
-27
@@ -1,3 +1,6 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
|
||||
@@ -7,34 +10,10 @@
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// enum type for device type
|
||||
type DeviceType uint8
|
||||
|
||||
// DeviceType specific parsing of information received from the sensor
|
||||
func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) {
|
||||
if d == DHT11 {
|
||||
temp = int16(buf[2])
|
||||
if buf[3]&0x80 > 0 {
|
||||
temp = -1 - temp
|
||||
}
|
||||
temp *= 10
|
||||
temp += int16(buf[3] & 0x0f)
|
||||
hum = 10*uint16(buf[0]) + uint16(buf[1])
|
||||
} else {
|
||||
hum = binary.LittleEndian.Uint16(buf[0:2])
|
||||
temp = int16(buf[3])<<8 + int16(buf[2]&0x7f)
|
||||
if buf[2]&0x80 > 0 {
|
||||
temp = -temp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Celsius and Fahrenheit temperature scales
|
||||
type TemperatureScale uint8
|
||||
|
||||
@@ -54,9 +33,6 @@ const (
|
||||
startTimeout = time.Millisecond * 200
|
||||
startingLow = time.Millisecond * 20
|
||||
|
||||
DHT11 DeviceType = iota
|
||||
DHT22
|
||||
|
||||
C TemperatureScale = iota
|
||||
F
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// DeviceType is the enum type for device type
|
||||
type DeviceType uint8
|
||||
|
||||
const (
|
||||
DHT11 DeviceType = iota
|
||||
DHT22
|
||||
)
|
||||
|
||||
// extractData parses information received from the sensor.
|
||||
// The 2 first buffers are for the humidity and
|
||||
// the 2 following corresponds to the temperature.
|
||||
func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) {
|
||||
switch d {
|
||||
case DHT11:
|
||||
hum = 10*uint16(buf[0]) + uint16(buf[1])
|
||||
temp = int16(buf[2])
|
||||
if buf[3]&0x80 > 0 {
|
||||
temp = -1 - temp
|
||||
}
|
||||
temp *= 10
|
||||
temp += int16(buf[3] & 0x0f)
|
||||
case DHT22:
|
||||
hum = binary.BigEndian.Uint16(buf[0:2])
|
||||
temp = int16(buf[2]&0x7f)<<8 + int16(buf[3])
|
||||
// the first bit corresponds to the sign bit
|
||||
if buf[2]&0x80 > 0 {
|
||||
temp = -temp
|
||||
}
|
||||
default:
|
||||
// keeping this for retro-compatibility but not tested
|
||||
hum = binary.LittleEndian.Uint16(buf[0:2])
|
||||
temp = int16(buf[3])<<8 + int16(buf[2]&0x7f)
|
||||
if buf[2]&0x80 > 0 {
|
||||
temp = -temp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeviceType_extractData(t *testing.T) {
|
||||
bitStr := "0000001010001100000000010101111111101110"
|
||||
buf := bitStringToBytes(bitStr)
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
d DeviceType
|
||||
buf []byte
|
||||
wantTemp int16
|
||||
wantHum uint16
|
||||
}{
|
||||
{
|
||||
// temp = 35.1C hum = 65.2%
|
||||
name: "DHT22", d: DHT22, buf: buf, wantTemp: 351, wantHum: 652,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
gotTemp, gotHum := tc.d.extractData(tc.buf)
|
||||
if gotTemp != tc.wantTemp {
|
||||
t.Errorf("extractData() gotTemp = %v, want %v", gotTemp, tc.wantTemp)
|
||||
}
|
||||
if gotHum != tc.wantHum {
|
||||
t.Errorf("extractData() gotHum = %v, want %v", gotHum, tc.wantHum)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func bitStringToBytes(s string) []byte {
|
||||
b := make([]byte, (len(s)+(8-1))/8)
|
||||
for i, r := range s {
|
||||
if r < '0' || r > '1' {
|
||||
panic("not in range")
|
||||
}
|
||||
b[i>>3] |= byte(r-'0') << uint(7-i&7)
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package espat
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
func (d *Device) ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error {
|
||||
if len(ssid) == 0 {
|
||||
return net.ErrWiFiMissingSSID
|
||||
}
|
||||
|
||||
d.SetWifiMode(WifiModeClient)
|
||||
return d.ConnectToAP(ssid, pass, int(timeout.Seconds()))
|
||||
}
|
||||
|
||||
func (d *Device) Disconnect() error {
|
||||
return d.DisconnectFromAP()
|
||||
}
|
||||
@@ -9,21 +9,22 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
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
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableColor() // enable color engine
|
||||
|
||||
for {
|
||||
|
||||
@@ -9,21 +9,22 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
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
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableGesture() // enable gesture engine
|
||||
|
||||
for {
|
||||
@@ -34,7 +35,7 @@ func main() {
|
||||
gesture := sensor.ReadGesture()
|
||||
print("Detected gesture: ")
|
||||
switch gesture {
|
||||
case apds9960.GESTURE_UP:
|
||||
case apds9960.GESTURE_UP: // the nRF52 chip is "up"
|
||||
println("Up")
|
||||
case apds9960.GESTURE_DOWN:
|
||||
println("Down")
|
||||
|
||||
@@ -9,21 +9,23 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
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
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
// use default settings
|
||||
sensor.Configure(apds9960.Configuration{})
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableProximity() // enable proximity engine
|
||||
|
||||
for {
|
||||
|
||||
@@ -12,7 +12,7 @@ func main() {
|
||||
dhtSensor := dht.New(pin, dht.DHT11)
|
||||
for {
|
||||
temp, hum, err := dhtSensor.Measurements()
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
fmt.Printf("Temperature: %02d.%d°C, Humidity: %02d.%d%%\n", temp/10, temp%10, hum/10, hum%10)
|
||||
} else {
|
||||
fmt.Printf("Could not take measurements from the sensor: %s\n", err.Error())
|
||||
|
||||
@@ -113,8 +113,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -99,8 +99,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -88,8 +88,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -108,8 +108,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -129,8 +129,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -91,8 +91,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ft6336"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func initDevices() (touch.Pointer, error) {
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
|
||||
resistiveTouch.Configure(ft6336.Config{})
|
||||
resistiveTouch.SetPeriodActive(0x00)
|
||||
|
||||
return resistiveTouch, nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
touchScreen, _ := initDevices()
|
||||
|
||||
for {
|
||||
touch := touchScreen.ReadTouchPoint()
|
||||
if touch.Z > 0 {
|
||||
//X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size
|
||||
//Z is 24 bit and is typically > 2000 for a touch
|
||||
println("touch:", touch.X, touch.Y, touch.Z)
|
||||
//Example of scaling for m5stack-core2's 320x240 display with 320x270 touch area
|
||||
println("screen:", (touch.X*320)>>16, (touch.Y*270)>>16)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/ft6336"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func initDevices() (touchPaintDisplay, touch.Pointer, error) {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
led.Low()
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.NoPin,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
display.FillScreen(color.RGBA{255, 255, 255, 255})
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
|
||||
resistiveTouch.Configure(ft6336.Config{})
|
||||
resistiveTouch.SetPeriodActive(0x00)
|
||||
|
||||
return display, resistiveTouch, nil
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
type touchPaintDisplay interface {
|
||||
drivers.Displayer
|
||||
FillRectangle(x, y, width, height int16, c color.RGBA) error
|
||||
DrawRectangle(x, y, w, h int16, c color.RGBA) error
|
||||
}
|
||||
|
||||
var (
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
black = color.RGBA{0, 0, 0, 255}
|
||||
red = color.RGBA{255, 0, 0, 255}
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
blue = color.RGBA{0, 0, 255, 255}
|
||||
magenta = color.RGBA{255, 0, 255, 255}
|
||||
yellow = color.RGBA{255, 255, 0, 255}
|
||||
cyan = color.RGBA{0, 255, 255, 255}
|
||||
|
||||
oldColor color.RGBA
|
||||
currentColor color.RGBA
|
||||
)
|
||||
|
||||
const (
|
||||
penRadius = 3
|
||||
boxSize = 30
|
||||
|
||||
Xmin = 0
|
||||
Xmax = 0xFFFF
|
||||
Ymin = 0
|
||||
Ymax = 0xFFFF
|
||||
)
|
||||
|
||||
func main() {
|
||||
display, resistiveTouch, _ := initDevices()
|
||||
|
||||
// fill the background and activate the backlight
|
||||
width, height := display.Size()
|
||||
display.FillRectangle(0, 0, width, height, black)
|
||||
|
||||
// make color selection boxes
|
||||
display.FillRectangle(0, 0, boxSize, boxSize, red)
|
||||
display.FillRectangle(boxSize, 0, boxSize, boxSize, yellow)
|
||||
display.FillRectangle(boxSize*2, 0, boxSize, boxSize, green)
|
||||
display.FillRectangle(boxSize*3, 0, boxSize, boxSize, cyan)
|
||||
display.FillRectangle(boxSize*4, 0, boxSize, boxSize, blue)
|
||||
display.FillRectangle(boxSize*5, 0, boxSize, boxSize, magenta)
|
||||
display.FillRectangle(boxSize*6, 0, boxSize, boxSize, black)
|
||||
display.FillRectangle(boxSize*7, 0, boxSize, boxSize, white)
|
||||
|
||||
// set the initial color to red and draw a box to highlight it
|
||||
oldColor = red
|
||||
currentColor = red
|
||||
display.DrawRectangle(0, 0, boxSize, boxSize, white)
|
||||
|
||||
last := touch.Point{}
|
||||
|
||||
// loop and poll for touches, including performing debouncing
|
||||
debounce := 0
|
||||
for {
|
||||
|
||||
point := resistiveTouch.ReadTouchPoint()
|
||||
touch := touch.Point{}
|
||||
if point.Z>>6 > 100 {
|
||||
rawX := mapval(point.X, Xmin, Xmax, 0, int(width))
|
||||
rawY := mapval(point.Y, Ymin, Ymax, 0, int(height))
|
||||
touch.X = rawX
|
||||
touch.Y = rawY
|
||||
touch.Z = 1
|
||||
} else {
|
||||
touch.X = 0
|
||||
touch.Y = 0
|
||||
touch.Z = 0
|
||||
}
|
||||
|
||||
if last.Z != touch.Z {
|
||||
debounce = 0
|
||||
last = touch
|
||||
} else if math.Abs(float64(touch.X-last.X)) > 4 ||
|
||||
math.Abs(float64(touch.Y-last.Y)) > 4 {
|
||||
debounce = 0
|
||||
last = touch
|
||||
} else if debounce > 1 {
|
||||
debounce = 0
|
||||
HandleTouch(display, last)
|
||||
} else if touch.Z > 0 {
|
||||
debounce++
|
||||
} else {
|
||||
last = touch
|
||||
debounce = 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// based on Arduino's "map" function
|
||||
func mapval(x int, inMin int, inMax int, outMin int, outMax int) int {
|
||||
return (x-inMin)*(outMax-outMin)/(inMax-inMin) + outMin
|
||||
}
|
||||
|
||||
func HandleTouch(display touchPaintDisplay, touch touch.Point) {
|
||||
|
||||
if int16(touch.Y) < boxSize {
|
||||
oldColor = currentColor
|
||||
x := int16(touch.X)
|
||||
switch {
|
||||
case x < boxSize:
|
||||
currentColor = red
|
||||
case x < boxSize*2:
|
||||
currentColor = yellow
|
||||
case x < boxSize*3:
|
||||
currentColor = green
|
||||
case x < boxSize*4:
|
||||
currentColor = cyan
|
||||
case x < boxSize*5:
|
||||
currentColor = blue
|
||||
case x < boxSize*6:
|
||||
currentColor = magenta
|
||||
case x < boxSize*7:
|
||||
currentColor = black
|
||||
case x < boxSize*8:
|
||||
currentColor = white
|
||||
}
|
||||
|
||||
if oldColor == currentColor {
|
||||
return
|
||||
}
|
||||
|
||||
display.DrawRectangle((x/boxSize)*boxSize, 0, boxSize, boxSize, white)
|
||||
switch oldColor {
|
||||
case red:
|
||||
x = 0
|
||||
case yellow:
|
||||
x = boxSize
|
||||
case green:
|
||||
x = boxSize * 2
|
||||
case cyan:
|
||||
x = boxSize * 3
|
||||
case blue:
|
||||
x = boxSize * 4
|
||||
case magenta:
|
||||
x = boxSize * 5
|
||||
case black:
|
||||
x = boxSize * 6
|
||||
case white:
|
||||
x = boxSize * 7
|
||||
}
|
||||
display.FillRectangle(int16(x), 0, boxSize, boxSize, oldColor)
|
||||
|
||||
}
|
||||
|
||||
if (int16(touch.Y) - penRadius) > boxSize {
|
||||
display.FillRectangle(
|
||||
int16(touch.X), int16(touch.Y), penRadius*2, penRadius*2, currentColor)
|
||||
}
|
||||
}
|
||||
@@ -9,28 +9,27 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
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
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := hts221.New(machine.I2C1)
|
||||
|
||||
sensor.Configure() // power on and calibrate
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
//go:build feather_m0 || feather_m4 || feather_m4_can || feather_nrf52840 || feather_nrf52840_sense || feather_stm32f405 || feather_rp2040
|
||||
// +build feather_m0 feather_m4 feather_m4_can feather_nrf52840 feather_nrf52840_sense feather_stm32f405 feather_rp2040
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.D5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.D6.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.D9
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D10, // LCD_DC,
|
||||
machine.D11, // LCD_SS_PIN,
|
||||
machine.D12, // LCD_RESET,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//go:build m5stack
|
||||
// +build m5stack
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.LCD_BL_PIN
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RST_PIN,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
led.Low()
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.NoPin,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
display.FillScreen(color.RGBA{255, 255, 255, 255})
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -72,7 +72,8 @@ func drawPng(display *ili9341.Device) error {
|
||||
}
|
||||
})
|
||||
|
||||
return png.Decode(p)
|
||||
_, err := png.Decode(p)
|
||||
return err
|
||||
}
|
||||
|
||||
func drawJpeg(display *ili9341.Device) error {
|
||||
@@ -84,7 +85,8 @@ func drawJpeg(display *ili9341.Device) error {
|
||||
}
|
||||
})
|
||||
|
||||
return jpeg.Decode(p)
|
||||
_, err := jpeg.Decode(p)
|
||||
return err
|
||||
}
|
||||
|
||||
func errorMessage(err error) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/irremote"
|
||||
)
|
||||
|
||||
var irCmdButtons = map[uint16]string{
|
||||
0xA2: "POWER",
|
||||
0xE2: "FUNC/STOP",
|
||||
0x62: "VOL+",
|
||||
0x22: "FAST BACK",
|
||||
0x02: "PAUSE",
|
||||
0xC2: "FAST FORWARD",
|
||||
0xE0: "DOWN",
|
||||
0xA8: "VOL-",
|
||||
0x90: "UP",
|
||||
0x98: "EQ",
|
||||
0xB0: "ST/REPT",
|
||||
0x68: "0",
|
||||
0x30: "1",
|
||||
0x18: "2",
|
||||
0x7A: "3",
|
||||
0x10: "4",
|
||||
0x38: "5",
|
||||
0x5A: "6",
|
||||
0x42: "7",
|
||||
0x4A: "8",
|
||||
0x52: "9",
|
||||
}
|
||||
|
||||
var (
|
||||
pinIRIn = machine.GP26
|
||||
ir irremote.ReceiverDevice
|
||||
)
|
||||
|
||||
func setupPins() {
|
||||
ir = irremote.NewReceiver(pinIRIn)
|
||||
ir.Configure()
|
||||
}
|
||||
|
||||
func irCallback(data irremote.Data) {
|
||||
msg := "Command: " + irCmdButtons[data.Command]
|
||||
if data.Flags&irremote.DataFlagIsRepeat != 0 {
|
||||
msg = msg + " (REPEAT)"
|
||||
}
|
||||
println(msg)
|
||||
}
|
||||
|
||||
func main() {
|
||||
setupPins()
|
||||
ir.SetCommandHandler(irCallback)
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/is31fl3731"
|
||||
)
|
||||
|
||||
// I2CAddress -- address of led matrix
|
||||
var I2CAddress uint8 = is31fl3731.I2C_ADDRESS_74
|
||||
|
||||
func main() {
|
||||
bus := machine.I2C0
|
||||
err := bus.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
println("could not configure I2C:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create driver for Adafruit 15x7 CharliePlex LED Matrix FeatherWing
|
||||
// (CharlieWing): https://www.adafruit.com/product/3163
|
||||
ledMatrix := is31fl3731.NewAdafruitCharlieWing15x7(bus, I2CAddress)
|
||||
|
||||
err = ledMatrix.Configure()
|
||||
if err != nil {
|
||||
println("could not configure is31fl3731 driver:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Fill the whole matrix on the frame #0 (visible by default)
|
||||
ledMatrix.Fill(is31fl3731.FRAME_0, uint8(3))
|
||||
|
||||
// Draw couple pixels on the frame #1 (not visible yet)
|
||||
ledMatrix.DrawPixelXY(is31fl3731.FRAME_1, uint8(0), uint8(0), uint8(10))
|
||||
ledMatrix.DrawPixelXY(is31fl3731.FRAME_1, uint8(14), uint8(6), uint8(10))
|
||||
|
||||
// There are 8 frames available, it's a good idea to draw on an invisible
|
||||
// frame and then switch to that frame to reduce flickering. Switch between
|
||||
// frame #0 and #1 in a loop to show animation:
|
||||
for {
|
||||
println("show frame #0...")
|
||||
ledMatrix.SetActiveFrame(is31fl3731.FRAME_0)
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
println("show frame #1...")
|
||||
ledMatrix.SetActiveFrame(is31fl3731.FRAME_1)
|
||||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/l3gd20"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
// Default address on most breakout boards.
|
||||
pcaAddr = 0x40
|
||||
)
|
||||
|
||||
bus := machine.I2C0
|
||||
|
||||
err := bus.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
gyro := l3gd20.NewI2C(bus, 105)
|
||||
err = gyro.Configure(l3gd20.Config{Range: l3gd20.Range_250})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
|
||||
var x, y, z int32
|
||||
for {
|
||||
err = gyro.Update()
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
x, y, z = gyro.AngularVelocity()
|
||||
println(x, y, z)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -9,29 +9,27 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
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
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := lps22hb.New(machine.I2C1)
|
||||
sensor.Configure()
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-17
@@ -3,37 +3,62 @@ package main
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm303agr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// LSM303AGR/MAG is connected to the I2C0 bus on micro:bit v1 (the same as P19/P20) and v2 (internal)
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
accel_mag := lsm303agr.New(machine.I2C0)
|
||||
|
||||
if !accel_mag.Connected() {
|
||||
println("LSM303AGR/MAG not connected!")
|
||||
return
|
||||
sensor := lsm303agr.New(machine.I2C0)
|
||||
err := sensor.Configure(lsm303agr.Configuration{}) //default settings
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
accel_mag.Configure(lsm303agr.Configuration{}) //default settings
|
||||
// you can specify the following options to adjust accuracy, sensor range or save power.
|
||||
// see https://github.com/tinygo-org/drivers/blob/release/lsm303agr/registers.go for details:
|
||||
/*
|
||||
sensor.Configure(lsm303agr.Configuration{
|
||||
AccelPowerMode: lsm303agr.ACCEL_POWER_NORMAL,
|
||||
AccelRange: lsm303agr.ACCEL_RANGE_2G,
|
||||
AccelDataRate: lsm303agr.ACCEL_DATARATE_100HZ,
|
||||
MagPowerMode: lsm303agr.MAG_POWER_NORMAL,
|
||||
MagSystemMode: lsm303agr.MAG_SYSTEM_CONTINUOUS,
|
||||
MagDataRate: lsm303agr.MAG_DATARATE_10HZ,
|
||||
})
|
||||
*/
|
||||
|
||||
for {
|
||||
|
||||
accel_x, accel_y, accel_z := accel_mag.ReadAcceleration()
|
||||
pitch, roll := accel_mag.ReadPitchRoll()
|
||||
mag_x, mag_y, mag_z := accel_mag.ReadMagneticField()
|
||||
heading := accel_mag.ReadCompass()
|
||||
temp, _ := accel_mag.ReadTemperature()
|
||||
if !sensor.Connected() {
|
||||
println("LSM303AGR/MAG not connected!")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// accel_x, accel_y, accel_z := sensor.ReadAcceleration()
|
||||
// println("ACCEL_X:", accel_x/100000, " ACCEL_Y:", accel_y/100000, " ACCEL_Z:", accel_z/100000)
|
||||
|
||||
// mag_x, mag_y, mag_z := sensor.ReadMagneticField()
|
||||
// println("MAG_X:", mag_x/100000, " MAG_Y:", mag_y/100000, " MAG_Z:", mag_z/100000)
|
||||
|
||||
pitch, roll, _ := sensor.ReadPitchRoll()
|
||||
println("Pitch:", float32(pitch)/100000, " Roll:", float32(roll)/100000)
|
||||
|
||||
heading, _ := sensor.ReadCompass()
|
||||
println("Heading:", float32(heading)/100000, "degrees")
|
||||
|
||||
temp, _ := sensor.ReadTemperature()
|
||||
println("Temperature:", float32(temp)/1000, "*C")
|
||||
|
||||
println("ACCEL_X:", accel_x, " ACCEL_Y:", accel_y, " ACCEL_Z:", accel_z)
|
||||
println("MAG_X:", mag_x, " MAG_Y:", mag_y, " MAG_Z:", mag_z)
|
||||
println("Pitch:", pitch, " Roll:", roll)
|
||||
println("Heading:", heading)
|
||||
println("Temperature:", temp/1000)
|
||||
println("\n")
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,16 +12,23 @@ func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
accel := lsm6ds3.New(machine.I2C0)
|
||||
accel.Configure(lsm6ds3.Configuration{})
|
||||
if !accel.Connected() {
|
||||
println("LSM6DS3 not connected")
|
||||
return
|
||||
err := accel.Configure(lsm6ds3.Configuration{})
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
x, y, z := accel.ReadAcceleration()
|
||||
if !accel.Connected() {
|
||||
println("LSM6DS3 not connected")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
x, y, z, _ := accel.ReadAcceleration()
|
||||
println("Acceleration:", float32(x)/1000000, float32(y)/1000000, float32(z)/1000000)
|
||||
x, y, z = accel.ReadRotation()
|
||||
x, y, z, _ = accel.ReadRotation()
|
||||
println("Gyroscope:", float32(x)/1000000, float32(y)/1000000, float32(z)/1000000)
|
||||
x, _ = accel.ReadTemperature()
|
||||
println("Degrees C", float32(x)/1000, "\n\n")
|
||||
|
||||
@@ -26,12 +26,18 @@ func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
device := lsm6dsox.New(machine.I2C0)
|
||||
device.Configure(lsm6dsox.Configuration{
|
||||
err := device.Configure(lsm6dsox.Configuration{
|
||||
AccelRange: lsm6dsox.ACCEL_2G,
|
||||
AccelSampleRate: lsm6dsox.ACCEL_SR_104,
|
||||
GyroRange: lsm6dsox.GYRO_250DPS,
|
||||
GyroSampleRate: lsm6dsox.GYRO_SR_104,
|
||||
})
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
@@ -46,8 +52,8 @@ func main() {
|
||||
calibrateGyro(device)
|
||||
}
|
||||
|
||||
ax, ay, az := device.ReadAcceleration()
|
||||
gx, gy, gz := device.ReadRotation()
|
||||
ax, ay, az, _ := device.ReadAcceleration()
|
||||
gx, gy, gz, _ := device.ReadRotation()
|
||||
t, _ := device.ReadTemperature()
|
||||
|
||||
if PLOTTER {
|
||||
@@ -64,7 +70,7 @@ func main() {
|
||||
|
||||
func calibrateGyro(device *lsm6dsox.Device) {
|
||||
for i := 0; i < 100; i++ {
|
||||
gx, gy, gz := device.ReadRotation()
|
||||
gx, gy, gz, _ := device.ReadRotation()
|
||||
cal[0] += float32(gx) / 1000000
|
||||
cal[1] += float32(gy) / 1000000
|
||||
cal[2] += float32(gz) / 1000000
|
||||
|
||||
@@ -41,7 +41,7 @@ func main() {
|
||||
|
||||
for {
|
||||
|
||||
if con, err := device.Connected(); !con || err != nil {
|
||||
if !device.Connected() {
|
||||
println("LSM9DS1 not connected")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
|
||||
@@ -29,6 +29,7 @@ func main() {
|
||||
driver.StopDisplayTest()
|
||||
driver.SetDecodeMode(4)
|
||||
driver.SetScanLimit(4)
|
||||
driver.SetIntensity(8)
|
||||
driver.StopShutdownMode()
|
||||
|
||||
for i := 1; i < int(digitNumber); i++ {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pca9685"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
// Default address on most breakout boards.
|
||||
pcaAddr = 0x40
|
||||
)
|
||||
err := machine.I2C0.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
d := pca9685.New(machine.I2C0, 0x40)
|
||||
err = d.IsConnected()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
err = d.Configure(pca9685.PWMConfig{Period: 1e9 / 200}) // 200Hz PWM
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
var value uint32
|
||||
step := d.Top() / 5
|
||||
for {
|
||||
for value = 0; value <= d.Top(); value += step {
|
||||
d.SetAll(value)
|
||||
dc := 100 * value / d.Top()
|
||||
println("set dc @", dc, "%")
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ScanI2CDev finds I2C devices on the bus and rreturns them inside
|
||||
// a slice. If slice is nil then no devices were found.
|
||||
func ScanI2CDev(bus machine.I2C) (addrs []uint8) {
|
||||
var addr, count uint8
|
||||
var err error
|
||||
w := []byte{1}
|
||||
// Count devices in first scan
|
||||
for addr = 1; addr < 127; addr++ {
|
||||
err = bus.Tx(uint16(addr), w, nil)
|
||||
if err == nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
// Allocate slice and populate slice with addresses
|
||||
addrs = make([]uint8, count)
|
||||
count = 0
|
||||
for addr = 1; addr < 127; addr++ {
|
||||
err = bus.Tx(uint16(addr), w, nil)
|
||||
if err == nil && count < uint8(len(addrs)) {
|
||||
addrs[count] = addr
|
||||
count++
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func run() error {
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
fmt.Fprintf(terminal, "ConnectToAP()\r\n")
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
}
|
||||
http.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/shtc3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
sensor := shtc3.New(machine.I2C0)
|
||||
|
||||
for {
|
||||
|
||||
sensor.WakeUp()
|
||||
|
||||
temp, humidity, _ := sensor.ReadTemperatureHumidity()
|
||||
t := fmt.Sprintf("%.2f", float32(temp)/1000)
|
||||
h := fmt.Sprintf("%.2f", float32(humidity)/100)
|
||||
println("Temperature:", t, "°C")
|
||||
println("Humidity", h, "%")
|
||||
|
||||
sensor.Sleep()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"math/rand"
|
||||
|
||||
"tinygo.org/x/drivers/ssd1289"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//The SSD1289 is configured in 16 bit parallel mode and requires 16 GPIOs
|
||||
//The Pin bus is the most flexible but ineffecient method it switches
|
||||
//individual pins on and off. If you are able to use consecutive pins
|
||||
//consider creating a more efficient bus implementation that uses
|
||||
//your microcontrollers built in "ports"
|
||||
//see rp2040bus.go for an example for the rapsberry pi pico
|
||||
bus := ssd1289.NewPinBus([16]machine.Pin{
|
||||
machine.GP4, //DB0
|
||||
machine.GP5, //DB1
|
||||
machine.GP6, //DB2
|
||||
machine.GP7, //DB3
|
||||
machine.GP8, //DB4
|
||||
machine.GP9, //DB5
|
||||
machine.GP10, //DB6
|
||||
machine.GP11, //DB7
|
||||
machine.GP12, //DB8
|
||||
machine.GP13, //DB9
|
||||
machine.GP14, //DB10
|
||||
machine.GP15, //DB11
|
||||
machine.GP16, //DB12
|
||||
machine.GP17, //DB13
|
||||
machine.GP18, //DB14
|
||||
machine.GP19, //DB15
|
||||
})
|
||||
|
||||
//Control pins for the SSD1289
|
||||
rs := machine.GP0
|
||||
wr := machine.GP1
|
||||
cs := machine.GP2
|
||||
rst := machine.GP3
|
||||
|
||||
display := ssd1289.New(rs, wr, cs, rst, bus)
|
||||
|
||||
display.Configure() //Sends intialization sequence to SSD1289.
|
||||
//!! After configure the display will contain random data and needs to be cleared
|
||||
|
||||
background := color.RGBA{0, 0, 0, 255} //Black
|
||||
display.FillDisplay(background) //Clears the display to the given color
|
||||
|
||||
for {
|
||||
//Draw random filled coloured rectangles
|
||||
x := int16(rand.Intn(120))
|
||||
w := int16(rand.Intn(120))
|
||||
|
||||
y := int16(rand.Intn(160))
|
||||
h := int16(rand.Intn(160))
|
||||
|
||||
r := uint8(rand.Intn(255))
|
||||
g := uint8(rand.Intn(255))
|
||||
b := uint8(rand.Intn(255))
|
||||
|
||||
c := color.RGBA{r, g, b, 255}
|
||||
|
||||
display.FillRect(x, y, w, h, c) //Fills the given rectangle the rest of the display is unaffected.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
// This example will periodically enable Continuous "Preamble" and "Wave" modes on 868.1 Mhz
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
const FREQ = 868100000
|
||||
|
||||
var (
|
||||
loraRadio *sx126x.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("\n# TinyGo Lora continuous Wave/Preamble test")
|
||||
println("# -----------------------------------------")
|
||||
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
// Create the driver
|
||||
loraRadio = sx126x.New(machine.SPI3)
|
||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
||||
|
||||
// Create RF Switch
|
||||
var radioSwitch rfswitch.CustomSwitch
|
||||
loraRadio.SetRfSwitch(radioSwitch)
|
||||
|
||||
state := loraRadio.DetectDevice()
|
||||
if !state {
|
||||
panic("sx126x not detected. ")
|
||||
}
|
||||
|
||||
// Prepare for Lora operation
|
||||
loraConf := sx126x.LoraConfig{
|
||||
Freq: FREQ,
|
||||
Bw: sx126x.SX126X_LORA_BW_500_0,
|
||||
Sf: sx126x.SX126X_LORA_SF9,
|
||||
Cr: sx126x.SX126X_LORA_CR_4_7,
|
||||
HeaderType: sx126x.SX126X_LORA_HEADER_EXPLICIT,
|
||||
Preamble: 12,
|
||||
Ldr: sx126x.SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF,
|
||||
Iq: sx126x.SX126X_LORA_IQ_STANDARD,
|
||||
Crc: sx126x.SX126X_LORA_CRC_ON,
|
||||
SyncWord: sx126x.SX126X_LORA_MAC_PRIVATE_SYNCWORD,
|
||||
LoraTxPowerDBm: 14,
|
||||
}
|
||||
loraRadio.LoraConfig(loraConf)
|
||||
|
||||
// Although LoraConfig has already configured most of Lora settings,
|
||||
// the following lines are still required to enable Continuous Preamble/Wave
|
||||
loraRadio.SetPacketType(sx126x.SX126X_PACKET_TYPE_LORA)
|
||||
loraRadio.SetRfFrequency(loraConf.Freq)
|
||||
loraRadio.SetModulationParams(loraConf.Sf, loraConf.Bw, loraConf.Cr, loraConf.Ldr)
|
||||
loraRadio.SetTxParams(loraConf.LoraTxPowerDBm, sx126x.SX126X_PA_RAMP_200U)
|
||||
|
||||
for {
|
||||
println("2 seconds in Continuous Preamble")
|
||||
loraRadio.SetStandby()
|
||||
loraRadio.SetTxContinuousPreamble()
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Continuous Preamble Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
println("2 seconds in Continuous Wave")
|
||||
loraRadio.SetTxContinuousWave()
|
||||
time.Sleep(2 * time.Second)
|
||||
println(" Continuous Wave Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(60 * time.Second)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
// In this example, a Lora packet will be sent every 10s
|
||||
// module will be in RX mode between two transmissions
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
|
||||
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
const FREQ = 868100000
|
||||
|
||||
const (
|
||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
||||
)
|
||||
|
||||
var (
|
||||
loraRadio *sx126x.Device
|
||||
txmsg = []byte("Hello TinyGO")
|
||||
)
|
||||
|
||||
// radioIntHandler will take care of radio interrupts
|
||||
func radioIntHandler(intr interrupt.Interrupt) {
|
||||
loraRadio.HandleInterrupt()
|
||||
}
|
||||
|
||||
func main() {
|
||||
println("\n# TinyGo Lora RX/TX test")
|
||||
println("# ----------------------")
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
// Create the driver
|
||||
loraRadio = sx126x.New(machine.SPI3)
|
||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
||||
|
||||
// Create RF Switch
|
||||
var radioSwitch rfswitch.CustomSwitch
|
||||
loraRadio.SetRfSwitch(radioSwitch)
|
||||
|
||||
// Detect the device
|
||||
state := loraRadio.DetectDevice()
|
||||
if !state {
|
||||
panic("sx126x not detected.")
|
||||
}
|
||||
|
||||
// Add interrupt handler for Radio IRQs
|
||||
intr := interrupt.New(stm32.IRQ_Radio_IRQ_Busy, radioIntHandler)
|
||||
intr.Enable()
|
||||
|
||||
loraConf := sx126x.LoraConfig{
|
||||
Freq: FREQ,
|
||||
Bw: sx126x.SX126X_LORA_BW_500_0,
|
||||
Sf: sx126x.SX126X_LORA_SF9,
|
||||
Cr: sx126x.SX126X_LORA_CR_4_7,
|
||||
HeaderType: sx126x.SX126X_LORA_HEADER_EXPLICIT,
|
||||
Preamble: 12,
|
||||
Ldr: sx126x.SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF,
|
||||
Iq: sx126x.SX126X_LORA_IQ_STANDARD,
|
||||
Crc: sx126x.SX126X_LORA_CRC_ON,
|
||||
SyncWord: sx126x.SX126X_LORA_MAC_PRIVATE_SYNCWORD,
|
||||
LoraTxPowerDBm: 20,
|
||||
}
|
||||
|
||||
loraRadio.LoraConfig(loraConf)
|
||||
|
||||
var count uint
|
||||
for {
|
||||
tStart := time.Now()
|
||||
|
||||
// Blocking RX for LORA_DEFAULT_RXTIMEOUT_MS
|
||||
println("Start Lora RX for 10 sec")
|
||||
for int(time.Now().Sub(tStart).Seconds()) < 10 {
|
||||
buf, err := loraRadio.LoraRx(LORA_DEFAULT_RXTIMEOUT_MS)
|
||||
|
||||
if err != nil {
|
||||
println("RX Error: ", err)
|
||||
} else if buf != nil {
|
||||
println("Packet Received: len=", len(buf), string(buf))
|
||||
}
|
||||
}
|
||||
println("END Lora RX")
|
||||
|
||||
println("LORA TX size=", len(txmsg))
|
||||
err := loraRadio.LoraTx(txmsg, LORA_DEFAULT_TXTIMEOUT_MS)
|
||||
if err != nil {
|
||||
println("TX Error:", err)
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//go:build gnse
|
||||
// +build gnse
|
||||
|
||||
/*
|
||||
Generic Node Sensor Edition
|
||||
RFSwitch
|
||||
|
||||
Disable Switch : PB8=OFF PA0=OFF PA1=OFF
|
||||
Enable RX : PB8=ON PA0=ON PA1=OFF
|
||||
Enable TX RFO LP : PB8=ON PA0=ON PA1=ON
|
||||
Enable TX RFO HP : PB8=ON PA0=OFF PA1=ON
|
||||
*/
|
||||
package rfswitch
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
var (
|
||||
rfstate int
|
||||
)
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.RF_FE_CTRL1.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RF_FE_CTRL2.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RF_FE_CTRL3.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
rfstate = -1 //Unknown
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
if mode == rfstate {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.RF_FE_CTRL1.Set(false)
|
||||
machine.RF_FE_CTRL2.Set(true)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
machine.RF_FE_CTRL1.Set(true)
|
||||
machine.RF_FE_CTRL2.Set(true)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.RF_FE_CTRL1.Set(true)
|
||||
machine.RF_FE_CTRL2.Set(false)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
}
|
||||
|
||||
rfstate = mode
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//go:build lorae5
|
||||
// +build lorae5
|
||||
|
||||
package radio
|
||||
|
||||
/*
|
||||
/!\ LoRa-E5 module ONLY transmits through RFO_HP:
|
||||
|
||||
Receive: PA4=1, PA5=0
|
||||
Transmit(high output power, SMPS mode): PA4=0, PA5=1
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.PA4.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PB5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.PA4.Set(true)
|
||||
machine.PB5.Set(false)
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
errors.New("RFSWITCH_TX_LP not supported ")
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.PA4.Set(false)
|
||||
machine.PB5.Set(true)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build nucleowl55jc
|
||||
// +build nucleowl55jc
|
||||
|
||||
/*
|
||||
Nucleo WL55JC1
|
||||
RFSwitch
|
||||
|
||||
+-----------+---------+------------+------------+
|
||||
| | FE_CTRL1 | FE_CTRL2 | FE_CTRL3 |
|
||||
| | (PC4) | (PC5) | (PC3) |
|
||||
+-----------+----------+-----------+------------+
|
||||
| TX_HP | LOW | HIGH | HIGH |
|
||||
| TX_LP | HIGH | HIGH | HIGH |
|
||||
| RX | HIGH | LOW | HIGH |
|
||||
+-----------+----------+-----------+------------+
|
||||
*/
|
||||
package rfswitch
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.PC4.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PC5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PC3.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.PC4.Set(false)
|
||||
machine.PC5.Set(true)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
machine.PC4.Set(true)
|
||||
machine.PC5.Set(true)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.PC4.Set(true)
|
||||
machine.PC5.Set(false)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build espat
|
||||
// +build espat
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"tinygo.org/x/drivers/espat"
|
||||
)
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
adaptor *espat.Device
|
||||
)
|
||||
|
||||
func initAdaptor() *espat.Device {
|
||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||
|
||||
adaptor = espat.New(uart)
|
||||
adaptor.Configure()
|
||||
|
||||
return adaptor
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// This example opens a TCP connection and sends some data,
|
||||
// for the purpose of testing speed and connectivity.
|
||||
//
|
||||
// You can open a server to accept connections from this program using:
|
||||
//
|
||||
// nc -w 5 -lk 8080
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
// access point info
|
||||
const ssid = ""
|
||||
const pass = ""
|
||||
|
||||
// IP address of the server aka "hub". Replace with your own info.
|
||||
const serverIP = ""
|
||||
|
||||
var buf = &bytes.Buffer{}
|
||||
|
||||
func main() {
|
||||
initAdaptor()
|
||||
|
||||
connectToAP()
|
||||
|
||||
for {
|
||||
sendBatch()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
println("Done.")
|
||||
}
|
||||
|
||||
func sendBatch() {
|
||||
|
||||
// make TCP connection
|
||||
ip := net.ParseIP(serverIP)
|
||||
raddr := &net.TCPAddr{IP: ip, Port: 8080}
|
||||
laddr := &net.TCPAddr{Port: 8080}
|
||||
|
||||
message("---------------\r\nDialing TCP connection")
|
||||
conn, err := net.DialTCP("tcp", laddr, raddr)
|
||||
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
||||
message(err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
n := 0
|
||||
w := 0
|
||||
start := time.Now()
|
||||
|
||||
// send data
|
||||
message("Sending data")
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
buf.Reset()
|
||||
fmt.Fprint(buf,
|
||||
"\r---------------------------- i == ", i, " ----------------------------"+
|
||||
"\r---------------------------- i == ", i, " ----------------------------")
|
||||
if w, err = conn.Write(buf.Bytes()); err != nil {
|
||||
println("error:", err.Error(), "\r")
|
||||
continue
|
||||
}
|
||||
n += w
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
ms := time.Now().Sub(start).Milliseconds()
|
||||
fmt.Fprint(buf, "\nWrote ", n, " bytes in ", ms, " ms\r\n")
|
||||
message(buf.String())
|
||||
|
||||
if _, err := conn.Write(buf.Bytes()); err != nil {
|
||||
println("error:", err.Error(), "\r")
|
||||
}
|
||||
|
||||
// Right now this code is never reached. Need a way to trigger it...
|
||||
println("Disconnecting TCP...")
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, err := adaptor.GetClientIP()
|
||||
for ; err != nil; ip, err = adaptor.GetClientIP() {
|
||||
message(err.Error())
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
message(ip)
|
||||
}
|
||||
|
||||
func message(msg string) {
|
||||
println(msg, "\r")
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//go:build rtl8720dn
|
||||
// +build rtl8720dn
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"device/sam"
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/rtl8720dn"
|
||||
)
|
||||
|
||||
var (
|
||||
adaptor *rtl8720dn.RTL8720DN
|
||||
|
||||
uart UARTx
|
||||
)
|
||||
|
||||
func initAdaptor() *rtl8720dn.RTL8720DN {
|
||||
adaptor, err := setupRTL8720DN()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
net.UseDriver(adaptor)
|
||||
|
||||
return adaptor
|
||||
}
|
||||
|
||||
func handleInterrupt(interrupt.Interrupt) {
|
||||
// should reset IRQ
|
||||
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||
}
|
||||
|
||||
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RTL8720D_CHIP_PU.Low()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
machine.RTL8720D_CHIP_PU.High()
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
|
||||
uart = UARTx{
|
||||
UART: &machine.UART{
|
||||
Buffer: machine.NewRingBuffer(),
|
||||
Bus: sam.SERCOM0_USART_INT,
|
||||
SERCOM: 0,
|
||||
},
|
||||
}
|
||||
|
||||
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||
|
||||
rtl := rtl8720dn.New(uart)
|
||||
//rtl.Debug(debug)
|
||||
|
||||
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rtl, nil
|
||||
}
|
||||
|
||||
type UARTx struct {
|
||||
*machine.UART
|
||||
}
|
||||
|
||||
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||
if u.Buffered() == 0 {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
return 0, nil
|
||||
}
|
||||
return u.UART.Read(p)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//go:build wifinina
|
||||
// +build wifinina
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"tinygo.org/x/drivers/wifinina"
|
||||
)
|
||||
|
||||
var (
|
||||
// default interface for the Arduino Nano33 IoT.
|
||||
spi = machine.NINA_SPI
|
||||
|
||||
// ESP32/ESP8266 chip that has the WIFININA firmware flashed on it
|
||||
adaptor *wifinina.Device
|
||||
)
|
||||
|
||||
func initAdaptor() *wifinina.Device {
|
||||
// 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,
|
||||
})
|
||||
|
||||
adaptor = wifinina.New(spi,
|
||||
machine.NINA_CS,
|
||||
machine.NINA_ACK,
|
||||
machine.NINA_GPIO0,
|
||||
machine.NINA_RESETN)
|
||||
adaptor.Configure()
|
||||
|
||||
return adaptor
|
||||
}
|
||||
@@ -128,19 +128,15 @@ func waitSerial() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
}
|
||||
|
||||
@@ -132,22 +132,18 @@ func waitSerial() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -104,14 +104,16 @@ func main() {
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
println(err.Error())
|
||||
|
||||
@@ -116,13 +116,16 @@ func publishing() {
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -151,21 +151,18 @@ func clearBuffer() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -113,14 +113,17 @@ func sendBatch() {
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -122,21 +122,18 @@ func makeHTTPSRequest() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -76,15 +76,17 @@ func main() {
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -124,22 +124,18 @@ func makeHTTPRequest() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil { // error connecting to AP
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !digispark && !arduino && !qtpy
|
||||
// +build !digispark,!arduino,!qtpy
|
||||
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3
|
||||
// +build !digispark,!arduino,!qtpy,!m5stamp_c3
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build qtpy || m5stamp_c3
|
||||
// +build qtpy m5stamp_c3
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = machine.WS2812
|
||||
var led = machine.NoPin
|
||||
@@ -5,11 +5,6 @@ package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = machine.NEOPIXELS
|
||||
var led = machine.NoPin
|
||||
|
||||
func init() {
|
||||
pwr := machine.NEOPIXELS_POWER
|
||||
pwr.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/xpt2046"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
clk := machine.GPIO0
|
||||
cs := machine.GPIO1
|
||||
din := machine.GPIO2
|
||||
dout := machine.GPIO3
|
||||
irq := machine.GPIO4
|
||||
|
||||
touchScreen := xpt2046.New(clk, cs, din, dout, irq)
|
||||
|
||||
touchScreen.Configure(&xpt2046.Config{
|
||||
Precision: 10, //Maximum number of samples for a single ReadTouchPoint to improve accuracy.
|
||||
})
|
||||
|
||||
for {
|
||||
|
||||
//Wait for a touch
|
||||
for !touchScreen.Touched() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
touch := touchScreen.ReadTouchPoint()
|
||||
//X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size
|
||||
//Z is 24 bit and is typically > 2000 for a touch
|
||||
println("touch:", touch.X, touch.Y, touch.Z)
|
||||
//Example of scaling for a 240x320 display
|
||||
println("screen:", (touch.X*240)>>16, (touch.Y*320)>>16)
|
||||
|
||||
//Wait for touch to end
|
||||
for touchScreen.Touched() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Package ft6336 provides a driver for the FT6336 I2C Self-Capacitive touch
|
||||
// panel controller.
|
||||
//
|
||||
// Datasheet: https://focuslcds.com/content/FT6236.pdf
|
||||
//
|
||||
package ft6336
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// Device wraps FT6336 I2C Self-Capacitive touch
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
buf []byte
|
||||
Address uint8
|
||||
intPin machine.Pin
|
||||
}
|
||||
|
||||
// New returns FT6336 device for the provided I2C bus using default address.
|
||||
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
|
||||
return &Device{
|
||||
bus: i2c,
|
||||
buf: make([]byte, 11),
|
||||
Address: Address,
|
||||
intPin: intPin,
|
||||
}
|
||||
}
|
||||
|
||||
// Config contains settings for FT6636.
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure the FT6336 device.
|
||||
func (d *Device) Configure(config Config) error {
|
||||
d.write1Byte(0xA4, 0x00)
|
||||
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGMode sets interrupt mode.
|
||||
// 0x00 : Interrupt Polling mode
|
||||
// 0x01 : Interrupt Trigger mode (default)
|
||||
func (d *Device) SetGMode(v uint8) {
|
||||
d.write1Byte(RegGMode, v)
|
||||
}
|
||||
|
||||
// GetGMode gets interrupt mode.
|
||||
func (d *Device) GetGMode() uint8 {
|
||||
return d.read8bit(RegGMode)
|
||||
}
|
||||
|
||||
// SetPeriodActive sets report rate in Active mode.
|
||||
func (d *Device) SetPeriodActive(v uint8) {
|
||||
d.write1Byte(RegPeriodActive, v)
|
||||
}
|
||||
|
||||
// GetPeriodActive gets report rate in Active mode.
|
||||
func (d *Device) GetPeriodActive() uint8 {
|
||||
return d.read8bit(RegPeriodActive)
|
||||
}
|
||||
|
||||
// GetFirmwareID gets firmware version.
|
||||
func (d *Device) GetFirmwareID() uint8 {
|
||||
return d.read8bit(RegFirmid)
|
||||
}
|
||||
|
||||
// Read reads the registers.
|
||||
func (d *Device) Read() []byte {
|
||||
d.bus.Tx(uint16(d.Address), []byte{0x02}, d.buf[:])
|
||||
return d.buf[:]
|
||||
}
|
||||
|
||||
// ReadTouchPoint reads a single touch.Point from the device. The maximum value
|
||||
// for each touch.Point is 0xFFFF.
|
||||
func (d *Device) ReadTouchPoint() touch.Point {
|
||||
d.Read()
|
||||
z := 0xFFFFF
|
||||
if d.buf[0] == 0 {
|
||||
z = 0
|
||||
}
|
||||
|
||||
//Scale X&Y to 16 bit for consistency across touch drivers
|
||||
return touch.Point{
|
||||
X: (int(d.buf[1]&0x0F)<<8 + int(d.buf[2])) * ((1 << 16) / 320),
|
||||
Y: (int(d.buf[3]&0x0F)<<8 + int(d.buf[4])) * ((1 << 16) / 270),
|
||||
Z: z,
|
||||
}
|
||||
}
|
||||
|
||||
// Touched returns if touched or not.
|
||||
func (d *Device) Touched() bool {
|
||||
p := d.ReadTouchPoint()
|
||||
return p.Z > 0
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package ft6336
|
||||
|
||||
// 0x00 DEV_MODE
|
||||
// 0x01 GEST_ID
|
||||
// 0x02 TD_STATUS
|
||||
// 0x03 P1_XH
|
||||
// 0x04 P1_XL
|
||||
// 0x05 P1_YH
|
||||
// 0x06 P1_YL
|
||||
// 0x07 P1_WEIGHT
|
||||
// 0x08 P1_MISC
|
||||
// 0x09 P2_XH
|
||||
// 0x0A P2_XL
|
||||
// 0x0B P2_YH
|
||||
// 0x0C P2_YL
|
||||
// 0x0D P2_WEIGHT
|
||||
// 0x0E P2_MISC
|
||||
// 0x80 TH_GROUP
|
||||
// 0x85 TH_DIFF
|
||||
// 0x86 CTRL
|
||||
// 0x87 TIMEENTERMONITOR
|
||||
// 0x88 PERIODACTIVE
|
||||
// 0x89 PERIODMONITOR
|
||||
// 0x91 RADIAN_VALUE
|
||||
// 0x92 OFFSET_LEFT_RIGHT
|
||||
// 0x93 OFFSET_UP_D
|
||||
// 0x94 DISTANCE_LE
|
||||
// 0x95 DISTANCE_UP
|
||||
// 0x96 DISTANCE_ZO
|
||||
// ...
|
||||
// 0xA1 LIB_VER_H
|
||||
// 0xA2 LIB_VER_L
|
||||
// 0xA3 CIPHER
|
||||
// 0xA4 G_MODE
|
||||
// 0xA5 PWR_MODE
|
||||
// 0xA6 FIRMID
|
||||
// 0xA8 FOCALTECH_ID
|
||||
// ...
|
||||
// 0xAF RELEASE_CODE_ID
|
||||
// ...
|
||||
// 0xBC STATE
|
||||
|
||||
const (
|
||||
Address = 0x38
|
||||
|
||||
RegPeriodActive = 0x88
|
||||
RegGMode = 0xA4
|
||||
RegFirmid = 0xA6
|
||||
)
|
||||
+3
-1
@@ -105,7 +105,8 @@ func (g *GPIO) Read(data []byte) (n int, err error) {
|
||||
data[i] = g.read()
|
||||
n++
|
||||
}
|
||||
g.reconfigureGPIOMode(machine.PinInput)
|
||||
g.rw.Low()
|
||||
g.reconfigureGPIOMode(machine.PinOutput)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ func (g *GPIO) read4BitMode() byte {
|
||||
g.en.High()
|
||||
data := (g.pins() << 4 & 0xF0)
|
||||
g.en.Low()
|
||||
|
||||
g.en.High()
|
||||
data |= (g.pins() & 0x0F)
|
||||
g.en.Low()
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ func (d *Device) Configure(cfg Config) error {
|
||||
}
|
||||
|
||||
if d.datalength == DATA_LENGTH_4BIT {
|
||||
d.bus.Write([]byte{DATA_LENGTH_4BIT >> 4})
|
||||
d.bus.Write([]byte{DATA_LENGTH_4BIT})
|
||||
}
|
||||
|
||||
// Busy flag is now accessible
|
||||
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
|
||||
FUNCTION_MODE = 0x20
|
||||
DATA_LENGTH_8BIT = FUNCTION_MODE | 0x10
|
||||
DATA_LENGTH_4BIT = FUNCTION_MODE | 0x0
|
||||
DATA_LENGTH_4BIT = FUNCTION_MODE | 0x2
|
||||
TWO_LINE = FUNCTION_MODE | 0x8
|
||||
ONE_LINE = FUNCTION_MODE | 0x0
|
||||
FONT_5X10 = FUNCTION_MODE | 0x4
|
||||
|
||||
@@ -101,7 +101,7 @@ func (d *Device) Configure(cfg Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay clears all texts on the display.
|
||||
// ClearDisplay clears all texts on the display and sets the cursor back to position (0, 0).
|
||||
func (d *Device) ClearDisplay() {
|
||||
d.sendCommand(DISPLAY_CLEAR)
|
||||
d.cursor.x = 0
|
||||
@@ -119,7 +119,8 @@ func (d *Device) Home() {
|
||||
|
||||
// SetCursor sets the cursor to a specific position (x, y).
|
||||
//
|
||||
// if y (row) is set larger than actual rows, it would be set to 0.
|
||||
// For example, on 16x2 LCDs the range of x (column) is 0~15 and y (row) is 0~1.
|
||||
// if y is larger than actual rows, it would be set to 0 (restart from first row).
|
||||
func (d *Device) SetCursor(x, y uint8) {
|
||||
rowOffset := []uint8{0x0, 0x40, 0x14, 0x54}
|
||||
if y > (d.height - 1) {
|
||||
@@ -139,11 +140,11 @@ func (d *Device) Print(data []byte) {
|
||||
if chr == '\n' {
|
||||
d.newLine()
|
||||
} else {
|
||||
d.cursor.x++
|
||||
if d.cursor.x >= d.width {
|
||||
d.newLine()
|
||||
}
|
||||
d.sendData(uint8(rune(chr)))
|
||||
d.cursor.x++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -21,6 +21,14 @@ type Device struct {
|
||||
temperatureZero float32
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Connected returns whether HTS221 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
@@ -29,14 +37,6 @@ func (d *Device) Connected() bool {
|
||||
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}
|
||||
|
||||
@@ -5,10 +5,10 @@ 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}
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -6,24 +6,20 @@ 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)
|
||||
// Configure sets up the HTS221 device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
|
||||
machine.HTS_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.HTS_PWR.High()
|
||||
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.I2C_PULLUP.High()
|
||||
// Wait a moment
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
// read calibration data
|
||||
d.calibration()
|
||||
// activate device and use block data update mode
|
||||
d.Power(true)
|
||||
}
|
||||
|
||||
+72
-46
@@ -8,9 +8,10 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Width int16
|
||||
Height int16
|
||||
Rotation Rotation
|
||||
Width int16
|
||||
Height int16
|
||||
Rotation Rotation
|
||||
DisplayInversion bool
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
@@ -28,6 +29,33 @@ type Device struct {
|
||||
rd machine.Pin
|
||||
}
|
||||
|
||||
var cmdBuf [6]byte
|
||||
|
||||
var initCmd = []byte{
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
PWCTR1, 1, 0x23, // Power control VRH[5:0]
|
||||
PWCTR2, 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
VMCTR1, 2, 0x3e, 0x28, // VCM control
|
||||
VMCTR2, 1, 0x86, // VCM control2
|
||||
MADCTL, 1, 0x48, // Memory Access Control
|
||||
VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
PIXFMT, 1, 0x55,
|
||||
FRMCTR1, 2, 0x00, 0x18,
|
||||
DFUNCTR, 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
GAMMASET, 1, 0x01, // Gamma curve selected
|
||||
GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
||||
GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
|
||||
}
|
||||
|
||||
// Configure prepares display for use
|
||||
func (d *Device) Configure(config Config) {
|
||||
|
||||
@@ -80,33 +108,15 @@ func (d *Device) Configure(config Config) {
|
||||
delay(150)
|
||||
}
|
||||
|
||||
initCmd := []byte{
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
PWCTR1, 1, 0x23, // Power control VRH[5:0]
|
||||
PWCTR2, 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
VMCTR1, 2, 0x3e, 0x28, // VCM control
|
||||
VMCTR2, 1, 0x86, // VCM control2
|
||||
MADCTL, 1, 0x48, // Memory Access Control
|
||||
VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
PIXFMT, 1, 0x55,
|
||||
FRMCTR1, 2, 0x00, 0x18,
|
||||
DFUNCTR, 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
GAMMASET, 1, 0x01, // Gamma curve selected
|
||||
GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
||||
GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
|
||||
if config.DisplayInversion {
|
||||
initCmd = append(initCmd, INVON, 0x80)
|
||||
}
|
||||
|
||||
initCmd = append(initCmd,
|
||||
SLPOUT, 0x80, // Exit Sleep
|
||||
DISPON, 0x80, // Display on
|
||||
0x00, // End of list
|
||||
}
|
||||
)
|
||||
for i, c := 0, len(initCmd); i < c; {
|
||||
cmd := initCmd[i]
|
||||
if cmd == 0x00 {
|
||||
@@ -239,34 +249,46 @@ func (d *Device) GetRotation() Rotation {
|
||||
// SetRotation changes the rotation of the device (clock-wise)
|
||||
func (d *Device) SetRotation(rotation Rotation) {
|
||||
madctl := uint8(0)
|
||||
switch rotation % 4 {
|
||||
case 0:
|
||||
switch rotation % 8 {
|
||||
case Rotation0:
|
||||
madctl = MADCTL_MX | MADCTL_BGR
|
||||
case 1:
|
||||
case Rotation90:
|
||||
madctl = MADCTL_MV | MADCTL_BGR
|
||||
case 2:
|
||||
case Rotation180:
|
||||
madctl = MADCTL_MY | MADCTL_BGR
|
||||
case 3:
|
||||
case Rotation270:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
case Rotation0Mirror:
|
||||
madctl = MADCTL_BGR
|
||||
case Rotation90Mirror:
|
||||
madctl = MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
case Rotation180Mirror:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_BGR
|
||||
case Rotation270Mirror:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
}
|
||||
d.sendCommand(MADCTL, []uint8{madctl})
|
||||
cmdBuf[0] = madctl
|
||||
d.sendCommand(MADCTL, cmdBuf[:1])
|
||||
d.rotation = rotation
|
||||
}
|
||||
|
||||
// SetScrollArea sets an area to scroll with fixed top/bottom or left/right parts of the display
|
||||
// Rotation affects scroll direction
|
||||
func (d *Device) SetScrollArea(topFixedArea, bottomFixedArea int16) {
|
||||
d.sendCommand(VSCRDEF, []uint8{
|
||||
uint8(topFixedArea >> 8), uint8(topFixedArea),
|
||||
uint8(d.height - topFixedArea - bottomFixedArea>>8),
|
||||
uint8(d.height - topFixedArea - bottomFixedArea),
|
||||
uint8(bottomFixedArea >> 8), uint8(bottomFixedArea),
|
||||
})
|
||||
cmdBuf[0] = uint8(topFixedArea >> 8)
|
||||
cmdBuf[1] = uint8(topFixedArea)
|
||||
cmdBuf[2] = uint8(d.height - topFixedArea - bottomFixedArea>>8)
|
||||
cmdBuf[3] = uint8(d.height - topFixedArea - bottomFixedArea)
|
||||
cmdBuf[4] = uint8(bottomFixedArea >> 8)
|
||||
cmdBuf[5] = uint8(bottomFixedArea)
|
||||
d.sendCommand(VSCRDEF, cmdBuf[:6])
|
||||
}
|
||||
|
||||
// SetScroll sets the vertical scroll address of the display.
|
||||
func (d *Device) SetScroll(line int16) {
|
||||
d.sendCommand(VSCRSADD, []uint8{uint8(line >> 8), uint8(line)})
|
||||
cmdBuf[0] = uint8(line >> 8)
|
||||
cmdBuf[1] = uint8(line)
|
||||
d.sendCommand(VSCRSADD, cmdBuf[:2])
|
||||
}
|
||||
|
||||
// StopScroll returns the display to its normal state
|
||||
@@ -280,16 +302,20 @@ func (d *Device) setWindow(x, y, w, h int16) {
|
||||
//y += d.rowOffset
|
||||
x1 := x + w - 1
|
||||
if x != d.x0 || x1 != d.x1 {
|
||||
d.sendCommand(CASET, []uint8{
|
||||
uint8(x >> 8), uint8(x), uint8(x1 >> 8), uint8(x1),
|
||||
})
|
||||
cmdBuf[0] = uint8(x >> 8)
|
||||
cmdBuf[1] = uint8(x)
|
||||
cmdBuf[2] = uint8(x1 >> 8)
|
||||
cmdBuf[3] = uint8(x1)
|
||||
d.sendCommand(CASET, cmdBuf[:4])
|
||||
d.x0, d.x1 = x, x1
|
||||
}
|
||||
y1 := y + h - 1
|
||||
if y != d.y0 || y1 != d.y1 {
|
||||
d.sendCommand(PASET, []uint8{
|
||||
uint8(y >> 8), uint8(y), uint8(y1 >> 8), uint8(y1),
|
||||
})
|
||||
cmdBuf[0] = uint8(y >> 8)
|
||||
cmdBuf[1] = uint8(y)
|
||||
cmdBuf[2] = uint8(y1 >> 8)
|
||||
cmdBuf[3] = uint8(y1)
|
||||
d.sendCommand(PASET, cmdBuf[:4])
|
||||
d.y0, d.y1 = y, y1
|
||||
}
|
||||
d.sendCommand(RAMWR, nil)
|
||||
|
||||
@@ -81,4 +81,9 @@ const (
|
||||
Rotation90 Rotation = 1 // 90 degrees clock-wise rotation
|
||||
Rotation180 Rotation = 2
|
||||
Rotation270 Rotation = 3
|
||||
|
||||
Rotation0Mirror Rotation = 4
|
||||
Rotation90Mirror Rotation = 5
|
||||
Rotation180Mirror Rotation = 6
|
||||
Rotation270Mirror Rotation = 7
|
||||
)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//go:build !atsamd51 && !atsamd21
|
||||
// +build !atsamd51,!atsamd21
|
||||
//go:build !atsamd51 && !atsame5x && !atsamd21
|
||||
// +build !atsamd51,!atsame5x,!atsamd21
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build atsamd51
|
||||
// +build atsamd51
|
||||
//go:build atsamd51 || atsame5x
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -773,10 +773,10 @@ func (d *decoder) convertToRGB() (image.Image, error) {
|
||||
|
||||
// Decode reads a JPEG image from r. Different from the standard package, the
|
||||
// decoded result will be received by the callback set by SetCallback().
|
||||
func Decode(r io.Reader) error {
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
var d decoder
|
||||
_, err := d.decode(r, false)
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a JPEG image without
|
||||
|
||||
+4
-4
@@ -965,7 +965,7 @@ func (d *decoder) checkHeader() error {
|
||||
|
||||
// Decode reads a PNG image from r. Different from the standard package, the
|
||||
// decoded result will be received by the callback set by SetCallback().
|
||||
func Decode(r io.Reader) error {
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
d := &decoder{
|
||||
r: r,
|
||||
crc: crc32.NewIEEE(),
|
||||
@@ -974,17 +974,17 @@ func Decode(r io.Reader) error {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
for d.stage != dsSeenIEND {
|
||||
if err := d.parseChunk(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a PNG image without
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
package irremote // import "tinygo.org/x/drivers/irremote"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NEC protocol references
|
||||
// https://www.sbprojects.net/knowledge/ir/nec.php
|
||||
// https://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol
|
||||
// https://simple-circuit.com/arduino-nec-remote-control-decoder/
|
||||
|
||||
// Data encapsulates the data received by the ReceiverDevice.
|
||||
type Data struct {
|
||||
// Code is the raw IR data received.
|
||||
Code uint32
|
||||
// Address is the decoded address from the IR data received.
|
||||
Address uint16
|
||||
// Command is the decoded command from the IR data recieved
|
||||
Command uint16
|
||||
// Flags provides additional information about the IR data received. See DataFlags
|
||||
Flags DataFlags
|
||||
}
|
||||
|
||||
// DataFlags provides bitwise flags representing various information about recieved IR data.
|
||||
type DataFlags uint16
|
||||
|
||||
// Valid values for DataFlags
|
||||
const (
|
||||
// DataFlagIsRepeat set indicates that the IR data is a repeat commmand
|
||||
DataFlagIsRepeat DataFlags = 1 << iota
|
||||
)
|
||||
|
||||
// CommandHandler defines the callback function used to provide IR data received by the ReceiverDevice.
|
||||
type CommandHandler func(data Data)
|
||||
|
||||
// nec_ir_state represents the various internal states used to decode the NEC IR protocol commands
|
||||
type nec_ir_state uint8
|
||||
|
||||
// Valid values for nec_ir_state
|
||||
const (
|
||||
lead_pulse_start nec_ir_state = iota // Start receiving IR data, beginning of 9ms lead pulse
|
||||
lead_space_start // End of 9ms lead pulse, start of 4.5ms space
|
||||
lead_space_end // End of 4.5ms space, start of 562µs pulse
|
||||
bit_read_start // End of 562µs pulse, start of 562µs or 1687µs space
|
||||
bit_read_end // End of 562µs or 1687µs space
|
||||
trail_pulse_end // End of 562µs trailing pulse
|
||||
)
|
||||
|
||||
// ReceiverDevice is the device for receiving IR commands
|
||||
type ReceiverDevice struct {
|
||||
pin machine.Pin // IR input pin.
|
||||
ch CommandHandler // client callback function
|
||||
necState nec_ir_state // internal state machine
|
||||
data Data // decoded data for client
|
||||
lastTime time.Time // used to track states
|
||||
bitIndex int // tracks which bit (0-31) of necCode is being read
|
||||
}
|
||||
|
||||
// NewReceiver returns a new IR receiver device
|
||||
func NewReceiver(pin machine.Pin) ReceiverDevice {
|
||||
return ReceiverDevice{pin: pin}
|
||||
}
|
||||
|
||||
// Configure configures the input pin for the IR receiver device
|
||||
func (ir *ReceiverDevice) Configure() {
|
||||
// The IR receiver sends logic HIGH when NOT receiving IR, and logic LOW when receiving IR
|
||||
ir.pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
}
|
||||
|
||||
// SetCommandHandler is used to start or stop receiving IR commands via a callback function (pass nil to stop)
|
||||
func (ir *ReceiverDevice) SetCommandHandler(ch CommandHandler) {
|
||||
ir.ch = ch
|
||||
ir.resetStateMachine()
|
||||
if ch != nil {
|
||||
// Start monitoring IR output pin for changes
|
||||
ir.pin.SetInterrupt(machine.PinFalling|machine.PinRising, ir.pinChange)
|
||||
} else {
|
||||
// Stop monitoring IR output pin for changes
|
||||
ir.pin.SetInterrupt(0, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// Internal helper function to reset state machine on protocol failure
|
||||
func (ir *ReceiverDevice) resetStateMachine() {
|
||||
ir.data = Data{}
|
||||
ir.bitIndex = 0
|
||||
ir.necState = lead_pulse_start
|
||||
}
|
||||
|
||||
// Internal pin rising/falling edge interrupt handler
|
||||
func (ir *ReceiverDevice) pinChange(pin machine.Pin) {
|
||||
/* Currently TinyGo is sending machine.NoPin (0xff) for all pins, at least on RP2040
|
||||
if pin != ir.pin {
|
||||
return // This is not the pin you're looking for
|
||||
}
|
||||
*/
|
||||
now := time.Now()
|
||||
duration := now.Sub(ir.lastTime)
|
||||
ir.lastTime = now
|
||||
switch ir.necState {
|
||||
case lead_pulse_start:
|
||||
if !ir.pin.Get() {
|
||||
// IR is 'on' (pin is pulled high and sent low when IR is received)
|
||||
ir.necState = lead_space_start // move to next state
|
||||
}
|
||||
case lead_space_start:
|
||||
if duration > time.Microsecond*9500 || duration < time.Microsecond*8500 {
|
||||
// Invalid interval for 9ms lead pulse. Reset
|
||||
ir.resetStateMachine()
|
||||
} else {
|
||||
// 9ms lead pulse detected, move to next state
|
||||
ir.necState = lead_space_end
|
||||
}
|
||||
case lead_space_end:
|
||||
if duration > time.Microsecond*5000 || duration < time.Microsecond*1750 {
|
||||
// Invalid interval for 4.5ms lead space OR 2.25ms repeat space. Reset
|
||||
ir.resetStateMachine()
|
||||
} else {
|
||||
// 4.5ms lead space OR 2.25ms repeat space detected
|
||||
if duration > time.Microsecond*3000 {
|
||||
// 4.5ms lead space detected, new code incoming, move to next state
|
||||
ir.resetStateMachine()
|
||||
ir.necState = bit_read_start
|
||||
} else {
|
||||
// 2.25ms repeat space detected.
|
||||
if ir.data.Code != 0 {
|
||||
// Valid repeat code. Invoke client callback with repeat flag set
|
||||
ir.data.Flags |= DataFlagIsRepeat
|
||||
if ir.ch != nil {
|
||||
ir.ch(ir.data)
|
||||
}
|
||||
ir.necState = lead_pulse_start
|
||||
} else {
|
||||
// ir.data is not in a valid state for a repeat. Reset
|
||||
ir.resetStateMachine()
|
||||
}
|
||||
}
|
||||
}
|
||||
case bit_read_start:
|
||||
if duration > time.Microsecond*700 || duration < time.Microsecond*400 {
|
||||
// Invalid interval for 562.5µs pulse. Reset
|
||||
ir.resetStateMachine()
|
||||
} else {
|
||||
// 562.5µs pulse detected, move to next state
|
||||
ir.necState = bit_read_end
|
||||
}
|
||||
case bit_read_end:
|
||||
if duration > time.Microsecond*1800 || duration < time.Microsecond*400 {
|
||||
// Invalid interval for 562.5µs space OR 1687.5µs space. Reset
|
||||
ir.resetStateMachine()
|
||||
} else {
|
||||
// 562.5µs OR 1687.5µs space detected
|
||||
mask := uint32((1 << (31 - ir.bitIndex)))
|
||||
if duration > time.Microsecond*1000 {
|
||||
// 1687.5µs space detected (logic 1) - Set bit
|
||||
ir.data.Code |= mask
|
||||
} else {
|
||||
// 562.5µs space detected (logic 0) - Clear bit
|
||||
ir.data.Code &^= mask
|
||||
}
|
||||
|
||||
ir.bitIndex++
|
||||
if ir.bitIndex > 31 {
|
||||
// We've read all bits for this code, move to next state
|
||||
ir.necState = trail_pulse_end
|
||||
} else {
|
||||
// Read next bit
|
||||
ir.necState = bit_read_start
|
||||
}
|
||||
}
|
||||
case trail_pulse_end:
|
||||
if duration > time.Microsecond*700 || duration < time.Microsecond*400 {
|
||||
// Invalid interval for trailing 562.5µs pulse. Reset
|
||||
ir.resetStateMachine()
|
||||
} else {
|
||||
// 562.5µs trailing pulse detected. Decode & validate data
|
||||
err := ir.decode()
|
||||
if err == irDecodeErrorNone {
|
||||
// Valid data, invoke client callback
|
||||
if ir.ch != nil {
|
||||
ir.ch(ir.data)
|
||||
}
|
||||
// around we go again. Note: we don't resetStateMachine() since repeat codes are now possible
|
||||
ir.necState = lead_pulse_start
|
||||
} else {
|
||||
ir.resetStateMachine()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error type for NEC format decoding
|
||||
type irDecodeError int
|
||||
|
||||
// Valid values for irDecodeError
|
||||
const (
|
||||
irDecodeErrorNone irDecodeError = iota // no error occurred
|
||||
irDecodeErrorInverseCheckFail // validation of inverse cmd does not match cmd
|
||||
)
|
||||
|
||||
func (ir *ReceiverDevice) decode() irDecodeError {
|
||||
// Decode cmd and inverse cmd and perform validation check
|
||||
cmd := uint8((ir.data.Code & 0xff00) >> 8)
|
||||
invCmd := uint8(ir.data.Code & 0xff)
|
||||
if cmd != ^invCmd {
|
||||
// Validation failure. cmd and inverse cmd do not match
|
||||
return irDecodeErrorInverseCheckFail
|
||||
}
|
||||
// cmd validation pass, decode address
|
||||
ir.data.Command = uint16(cmd)
|
||||
addrLow := uint8((ir.data.Code & 0xff000000) >> 24)
|
||||
addrHigh := uint8((ir.data.Code & 0x00ff0000) >> 16)
|
||||
if addrHigh == ^addrLow {
|
||||
// addrHigh is inverse of addrLow. This is not a valid 16-bit address in extended NEC coding
|
||||
// since it is indistinguishable from 8-bit address with inverse validation. Use the 8-bit address
|
||||
ir.data.Address = uint16(addrLow)
|
||||
} else {
|
||||
// 16-bit extended NEC address
|
||||
ir.data.Address = (uint16(addrHigh) << 8) | uint16(addrLow)
|
||||
}
|
||||
// Clear repeat flag
|
||||
ir.data.Flags &^= DataFlagIsRepeat
|
||||
return irDecodeErrorNone
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
// Package is31fl3731 provides a driver for the Lumissil IS31FL3731 matrix LED
|
||||
// driver.
|
||||
//
|
||||
// Driver supports following layouts:
|
||||
// - any custom LED matrix layout
|
||||
// - Adafruit 15x7 CharliePlex LED Matrix FeatherWing (CharlieWing)
|
||||
// https://www.adafruit.com/product/3163
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf
|
||||
//
|
||||
// This driver inspired by Adafruit Python driver:
|
||||
// https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3731
|
||||
//
|
||||
package is31fl3731
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device implements TinyGo driver for Lumissil IS31FL3731 matrix LED driver
|
||||
type Device struct {
|
||||
Address uint8
|
||||
bus drivers.I2C
|
||||
|
||||
// Currently selected command register (one of the frame registers or the
|
||||
// function register)
|
||||
selectedCommand uint8
|
||||
}
|
||||
|
||||
// Configure chip for operating as a LED matrix display
|
||||
func (d *Device) Configure() (err error) {
|
||||
// Shutdown software
|
||||
err = d.writeFunctionRegister(SET_SHUTDOWN, []byte{SOFTWARE_OFF})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to shutdown: %w", err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
// Wake up software
|
||||
err = d.writeFunctionRegister(SET_SHUTDOWN, []byte{SOFTWARE_ON})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wake up: %w", err)
|
||||
}
|
||||
|
||||
// Set display to a picture mode ("auto frame play mode" and "audio frame play
|
||||
// mode" are not supported in this version of the driver)
|
||||
err = d.writeFunctionRegister(SET_DISPLAY_MODE, []byte{DISPLAY_MODE_PICTURE})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to switch to a picture move: %w", err)
|
||||
}
|
||||
|
||||
// Enable LEDs that are present (soldered) on the board. From the datasheet:
|
||||
// LEDs which are no connected must be off by LED Control Register (Frame
|
||||
// Registers) or it will affect other LEDs
|
||||
err = d.enableLEDs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to enable LEDs: %w", err)
|
||||
}
|
||||
|
||||
// Disable audiosync
|
||||
err = d.writeFunctionRegister(SET_AUDIOSYNC, []byte{AUDIOSYNC_OFF})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to disable audiosync: %w", err)
|
||||
}
|
||||
|
||||
// Clear all frames
|
||||
for frame := FRAME_0; frame <= FRAME_7; frame++ {
|
||||
err = d.Clear(frame)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clear frame %d: %w", frame, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 1st frame is displayed by default
|
||||
err = d.SetActiveFrame(FRAME_0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set active frame: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// selectCommand selects command register, can be:
|
||||
// - frame registers 0-7
|
||||
// - function register
|
||||
func (d *Device) selectCommand(command uint8) (err error) {
|
||||
if command != d.selectedCommand {
|
||||
d.selectedCommand = command
|
||||
return d.bus.WriteRegister(d.Address, COMMAND, []byte{command})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeFunctionRegister selects the function register and writes data into it
|
||||
func (d *Device) writeFunctionRegister(operation uint8, data []byte) (err error) {
|
||||
err = d.selectCommand(FUNCTION)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.bus.WriteRegister(d.Address, operation, data)
|
||||
}
|
||||
|
||||
// enableLEDs enables only LEDs that are soldered on the set board. Enabled
|
||||
// all 16x9 LEDs by default
|
||||
func (d *Device) enableLEDs() (err error) {
|
||||
for frame := FRAME_0; frame <= FRAME_7; frame++ {
|
||||
err = d.selectCommand(frame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Enable every LED (16 columns x 9 rows)
|
||||
for i := uint8(0); i < 16; i++ {
|
||||
err = d.bus.WriteRegister(d.Address, i, []byte{0xFF})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setPixelPWD sets individual pixel's PWM value [0-255] on the selected frame
|
||||
func (d *Device) setPixelPWD(frame, n, value uint8) (err error) {
|
||||
err = d.selectCommand(frame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.bus.WriteRegister(d.Address, LED_PWM_OFFSET+n, []byte{value})
|
||||
}
|
||||
|
||||
// SetActiveFrame sets frame to display with LEDs
|
||||
func (d *Device) SetActiveFrame(frame uint8) (err error) {
|
||||
if frame > FRAME_7 {
|
||||
return fmt.Errorf("frame %d is out of valid range [0-7]", frame)
|
||||
}
|
||||
|
||||
return d.writeFunctionRegister(SET_ACTIVE_FRAME, []byte{frame})
|
||||
}
|
||||
|
||||
// Fill the whole frame with provided PWM value [0-255]
|
||||
func (d *Device) Fill(frame, value uint8) (err error) {
|
||||
if frame > FRAME_7 {
|
||||
return fmt.Errorf("frame %d is out of valid range [0-7]", frame)
|
||||
}
|
||||
|
||||
err = d.selectCommand(frame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := make([]byte, 24)
|
||||
for i := range data {
|
||||
data[i] = value
|
||||
}
|
||||
|
||||
for i := uint8(0); i < 6; i++ {
|
||||
err = d.bus.WriteRegister(d.Address, LED_PWM_OFFSET+i*24, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clear the whole frame
|
||||
func (d *Device) Clear(frame uint8) (err error) {
|
||||
return d.Fill(frame, 0x00)
|
||||
}
|
||||
|
||||
// DrawPixelIndex draws a single pixel on the selected frame by its index with
|
||||
// provided PWM value [0-255]
|
||||
func (d *Device) DrawPixelIndex(frame, index, value uint8) (err error) {
|
||||
if frame > FRAME_7 {
|
||||
return fmt.Errorf("frame %d is out of valid range [0-7]", frame)
|
||||
}
|
||||
|
||||
return d.setPixelPWD(frame, index, value)
|
||||
}
|
||||
|
||||
// DrawPixelXY draws a single pixel on the selected frame by its XY coordinates
|
||||
// with provided PWM value [0-255]. Raw LEDs layout assumed to be a 16x9 matrix,
|
||||
// and can be used with any custom board that has IS31FL3731 driver.
|
||||
func (d *Device) DrawPixelXY(frame, x, y, value uint8) (err error) {
|
||||
return d.setPixelPWD(frame, 16*x+y, value)
|
||||
}
|
||||
|
||||
// New creates a raw driver w/o any preset board layout.
|
||||
// Addresses:
|
||||
// - 0x74 (AD pin connected to GND)
|
||||
// - 0x75 (AD pin connected to SCL)
|
||||
// - 0x76 (AD pin connected to SDA)
|
||||
// - 0x77 (AD pin connected to VCC)
|
||||
func New(bus drivers.I2C, address uint8) Device {
|
||||
return Device{
|
||||
Address: address,
|
||||
bus: bus,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package is31fl3731
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// DeviceAdafruitCharlieWing15x7 implements TinyGo driver for Lumissil
|
||||
// IS31FL3731 matrix LED driver on Adafruit 15x7 CharliePlex LED Matrix
|
||||
// FeatherWing (CharlieWing) board: https://www.adafruit.com/product/3163
|
||||
type DeviceAdafruitCharlieWing15x7 struct {
|
||||
Device
|
||||
}
|
||||
|
||||
// enableLEDs enables only LEDs that are soldered on the Adafruit CharlieWing
|
||||
// board. The board has following LEDs matrix layout:
|
||||
//
|
||||
// "o" - connected (soldered) LEDs
|
||||
// "x" - not connected LEDs
|
||||
//
|
||||
// + - - - - - - - - - - - - - - +
|
||||
// | + - - - - - - - - - - - - + |
|
||||
// | | | |
|
||||
// | | v v
|
||||
// +---------------------------------+
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | o o o o o o o o o o o o o o o x |
|
||||
// | x x x x x x x x x x x x x x x x |
|
||||
// +---------------------------------+
|
||||
// ^ ^ | |
|
||||
// | | ... - - + |
|
||||
// | + - - - - - - - - - - - - - +
|
||||
// |
|
||||
// start (address 0x00)
|
||||
//
|
||||
func (d *DeviceAdafruitCharlieWing15x7) enableLEDs() (err error) {
|
||||
for frame := FRAME_0; frame <= FRAME_7; frame++ {
|
||||
err = d.selectCommand(frame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Enable left half
|
||||
for i := uint8(0); i < 16; i += 2 {
|
||||
err = d.bus.WriteRegister(d.Address, i, []byte{0b11111110})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Enable right half
|
||||
for i := uint8(3); i < 16; i += 2 {
|
||||
err = d.bus.WriteRegister(d.Address, i, []byte{0b01111111})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Disable invisible column on the right side
|
||||
err = d.bus.WriteRegister(d.Address, 1, []byte{0b00000000})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DrawPixelXY draws a single pixel on the selected frame by its XY coordinates
|
||||
// with provided PWM value [0-255]
|
||||
func (d *DeviceAdafruitCharlieWing15x7) DrawPixelXY(frame, x, y, value uint8) (err error) {
|
||||
var index uint8
|
||||
|
||||
if x >= 15 {
|
||||
return fmt.Errorf("invalid value: X is out of range [0, 15]")
|
||||
} else if y >= 7 {
|
||||
return fmt.Errorf("invalid value: Y is out of range [0, 7]")
|
||||
}
|
||||
|
||||
// Board is one pixel shorter (7 vs 8 supported pixels)
|
||||
if x < 8 {
|
||||
index = 16*x + y + 1
|
||||
} else {
|
||||
index = 16*(16-x) - y - 1 - 1
|
||||
}
|
||||
|
||||
return d.setPixelPWD(frame, index, value)
|
||||
}
|
||||
|
||||
// NewAdafruitCharlieWing15x7 creates a new driver with Adafruit 15x7
|
||||
// CharliePlex LED Matrix FeatherWing (CharlieWing) layout.
|
||||
// Available addresses:
|
||||
// - 0x74 (default)
|
||||
// - 0x77 (when the address jumper soldered)
|
||||
func NewAdafruitCharlieWing15x7(bus drivers.I2C, address uint8) DeviceAdafruitCharlieWing15x7 {
|
||||
return DeviceAdafruitCharlieWing15x7{
|
||||
Device: Device{
|
||||
Address: address,
|
||||
bus: bus,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package is31fl3731
|
||||
|
||||
// Registers. Names taken from the datasheet:
|
||||
// https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf
|
||||
const (
|
||||
// AD pin connected to GND
|
||||
I2C_ADDRESS_74 uint8 = 0x74
|
||||
// AD pin connected to SCL
|
||||
I2C_ADDRESS_75 uint8 = 0x75
|
||||
// AD pin connected to SDA
|
||||
I2C_ADDRESS_76 uint8 = 0x76
|
||||
// AD pin connected to VCC
|
||||
I2C_ADDRESS_77 uint8 = 0x77
|
||||
|
||||
// Main command register
|
||||
COMMAND uint8 = 0xFD
|
||||
|
||||
// Commands for each of 8 frames
|
||||
FRAME_0 uint8 = 0x00
|
||||
FRAME_1 uint8 = 0x01
|
||||
FRAME_2 uint8 = 0x02
|
||||
FRAME_3 uint8 = 0x03
|
||||
FRAME_4 uint8 = 0x04
|
||||
FRAME_5 uint8 = 0x05
|
||||
FRAME_6 uint8 = 0x06
|
||||
FRAME_7 uint8 = 0x07
|
||||
|
||||
// Command to set configuration
|
||||
FUNCTION uint8 = 0x0B
|
||||
|
||||
// Configuration:
|
||||
SET_DISPLAY_MODE uint8 = 0x00
|
||||
SET_ACTIVE_FRAME uint8 = 0x01
|
||||
SET_AUDIOSYNC uint8 = 0x06
|
||||
SET_SHUTDOWN uint8 = 0x0A
|
||||
|
||||
// Configuration: display mode
|
||||
DISPLAY_MODE_PICTURE uint8 = 0x00
|
||||
|
||||
// Configuration: audiosync (enable audio signal to modulate the intensity of
|
||||
// the matrix)
|
||||
AUDIOSYNC_OFF uint8 = 0x00
|
||||
AUDIOSYNC_ON uint8 = 0x01
|
||||
|
||||
// Configuration: software shutdown
|
||||
SOFTWARE_OFF uint8 = 0x00
|
||||
SOFTWARE_ON uint8 = 0x01
|
||||
|
||||
// Frame LEDs
|
||||
LED_CONTROL_OFFSET uint8 = 0x00 // to on/off each LED
|
||||
LED_PWM_OFFSET uint8 = 0x24 // to set PWM (0-255) for each LED
|
||||
)
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package l3gd20
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
fifoLen = 32 * 3 * 2
|
||||
)
|
||||
|
||||
type DevI2C struct {
|
||||
addr uint8
|
||||
// sensitivity or range.
|
||||
mul int32
|
||||
bus drivers.I2C
|
||||
buf [1]byte
|
||||
// gyro databuf.
|
||||
databuf [6]byte
|
||||
data [3]int32
|
||||
}
|
||||
|
||||
func NewI2C(bus drivers.I2C, addr uint8) *DevI2C {
|
||||
return &DevI2C{
|
||||
addr: addr,
|
||||
bus: bus,
|
||||
mul: sensMul250,
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes and configures the device.
|
||||
func (d *DevI2C) Configure(cfg Config) error {
|
||||
err := cfg.validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = d.Reboot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Reset then switch to normal mode and enable all three channels.
|
||||
err = d.write8(CTRL_REG1, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = d.write8(CTRL_REG1, reg1NormalBits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Reset REG2 values to default
|
||||
err = d.write8(CTRL_REG3, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set sensitivity
|
||||
switch cfg.Range {
|
||||
case 1: // debugging range
|
||||
d.mul = 1
|
||||
cfg.Range = Range_2000
|
||||
case Range_250:
|
||||
d.mul = sensMul250
|
||||
case Range_500:
|
||||
d.mul = sensMul500
|
||||
case Range_2000:
|
||||
d.mul = sensMul2000
|
||||
default:
|
||||
return ErrBadRange
|
||||
}
|
||||
err = d.write8(CTRL_REG4, cfg.Range)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Finally verify whomai register and return error if
|
||||
// board is not who it says it is. Some counterfeit boards
|
||||
// have incorrect whomai but can still be used.
|
||||
whoami, err := d.read8(WHOAMI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if whoami != expectedWHOAMI && whoami != expectedWHOAMI_H {
|
||||
return ErrBadIdentity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DevI2C) Update() error {
|
||||
err := d.bus.ReadRegister(d.addr, OUT_X_L, d.databuf[:2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = d.bus.ReadRegister(d.addr, OUT_Y_L, d.databuf[2:4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = d.bus.ReadRegister(d.addr, OUT_Z_L, d.databuf[4:6])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
x := int16(binary.LittleEndian.Uint16(d.databuf[0:]))
|
||||
y := int16(binary.LittleEndian.Uint16(d.databuf[2:]))
|
||||
z := int16(binary.LittleEndian.Uint16(d.databuf[4:]))
|
||||
d.data[0] = d.mul * int32(x)
|
||||
d.data[1] = d.mul * int32(y)
|
||||
d.data[2] = d.mul * int32(z)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reboot sets reboot bit in CTRL_REG5 to true and unsets it.
|
||||
func (d *DevI2C) Reboot() error {
|
||||
reg5, err := d.read8(CTRL_REG5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Write reboot bit and then unset it.
|
||||
err = d.write8(CTRL_REG5, reg5|reg5RebootBit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(50 * time.Microsecond)
|
||||
return d.write8(CTRL_REG5, reg5&^reg5RebootBit)
|
||||
}
|
||||
|
||||
// AngularVelocity returns result in microradians per second.
|
||||
func (d *DevI2C) AngularVelocity() (x, y, z int32) {
|
||||
return d.data[0], d.data[1], d.data[2]
|
||||
}
|
||||
|
||||
// func (d DevI2C) Update(measurement)
|
||||
|
||||
func (d DevI2C) read8(reg uint8) (byte, error) {
|
||||
err := d.bus.ReadRegister(d.addr, reg, d.buf[:1])
|
||||
return d.buf[0], err
|
||||
}
|
||||
|
||||
func (d DevI2C) write8(reg uint8, val byte) error {
|
||||
d.buf[0] = val
|
||||
return d.bus.WriteRegister(d.addr, reg, d.buf[:1])
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package l3gd20
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrBadIdentity = errors.New("got unexpected identity from WHOMAI")
|
||||
ErrBadRange = errors.New("bad range configuration value")
|
||||
)
|
||||
|
||||
// Sensitivity factors
|
||||
const (
|
||||
// range at bits 4-5
|
||||
// 00 = 250 dps
|
||||
// 01 = 500 dps
|
||||
// 10 = 2000 dps
|
||||
// 11 = 2000 dps
|
||||
rangePos = 4
|
||||
Range_250 = 0b00 << rangePos // 8.75 mdps/digit
|
||||
Range_500 = 0b01 << rangePos // 17.5 mdps/digit
|
||||
Range_2000 = 0b11 << rangePos // 70 mdps/digit
|
||||
rangebits = Range_250 | Range_500 | Range_2000
|
||||
|
||||
// Sensitivities for degrees
|
||||
sensDiv250dps = 800
|
||||
sensDiv500dps = 400
|
||||
sensDiv2000dps = 100
|
||||
sens_250 = 7. / sensDiv250dps // Sensitivity at 250 dps
|
||||
sens_500 = 7. / sensDiv500dps // Sensitivity at 500 dps
|
||||
sens_2000 = 7. / sensDiv2000dps // Sensitivity at 500 dp
|
||||
|
||||
// 1e6*Pi/180. = 17453.292519943298 (constant for Degree to micro radians conversion)
|
||||
// sensitivities for radians
|
||||
sensMul250 = 7 * 1745329 / 100 / sensDiv250dps
|
||||
sensMul500 = 7 * 1745329 / 100 / sensDiv500dps
|
||||
sensMul2000 = 7 * 1745329 / 100 / sensDiv2000dps
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Range uint8
|
||||
}
|
||||
|
||||
// validate scans config for invalid data and returns non-nil
|
||||
// error indicating what data must be modified.
|
||||
func (cfg *Config) validate() error {
|
||||
if cfg.Range&^rangebits != 0 && cfg.Range != 1 {
|
||||
return ErrBadRange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package l3gd20
|
||||
|
||||
// Expected identification number for L3GD20.
|
||||
const (
|
||||
// For L3GD20
|
||||
expectedWHOAMI = 0xD4
|
||||
// For L3GD20H
|
||||
expectedWHOAMI_H = 0xD7
|
||||
)
|
||||
|
||||
// Register bits masks
|
||||
const (
|
||||
reg5RebootBit = 1 << 7
|
||||
reg5FIFOEnableBit = 1 << 6
|
||||
reg1NormalBits = 0b1111
|
||||
)
|
||||
|
||||
// Register addresses. Comments from https://github.com/adafruit/Adafruit_L3GD20_U/blob/master/Adafruit_L3GD20_U.cpp
|
||||
const (
|
||||
// The Slave ADdress (SAD) associated with the L3GD20 is 110101xb
|
||||
I2CAddr = 0b1101011
|
||||
// The SDO pin can be used to modify the less significant bit of the device address.
|
||||
I2CAddrSDOLow = 0b1101010
|
||||
WHOAMI uint8 = 0x0F
|
||||
// CTRL_REG1 (0x20)
|
||||
// ====================================================================
|
||||
// BIT Symbol Description Default
|
||||
// --- ------ --------------------------------------------- -------
|
||||
// 7-6 DR1/0 Output data rate 00
|
||||
// 5-4 BW1/0 Bandwidth selection 00
|
||||
// 3 PD 0 = Power-down mode, 1 = normal/sleep mode 0
|
||||
// 2 ZEN Z-axis enable (0 = disabled, 1 = enabled) 1
|
||||
// 1 YEN Y-axis enable (0 = disabled, 1 = enabled) 1
|
||||
// 0 XEN X-axis enable (0 = disabled, 1 = enabled) 1
|
||||
CTRL_REG1 uint8 = 0x20
|
||||
// Set CTRL_REG2 (0x21)
|
||||
// ====================================================================
|
||||
// BIT Symbol Description Default
|
||||
// --- ------ --------------------------------------------- -------
|
||||
// 5-4 HPM1/0 High-pass filter mode selection 00
|
||||
// 3-0 HPCF3..0 High-pass filter cutoff frequency selection 0000
|
||||
CTRL_REG2 uint8 = 0x21
|
||||
// CTRL_REG3 (0x22)
|
||||
// ====================================================================
|
||||
// BIT Symbol Description Default
|
||||
// --- ------ --------------------------------------------- -------
|
||||
// 7 I1_Int1 Interrupt enable on INT1 (0=disable,1=enable) 0
|
||||
// 6 I1_Boot Boot status on INT1 (0=disable,1=enable) 0
|
||||
// 5 H-Lactive Interrupt active config on INT1 (0=high,1=low) 0
|
||||
// 4 PP_OD Push-Pull/Open-Drain (0=PP, 1=OD) 0
|
||||
// 3 I2_DRDY Data ready on DRDY/INT2 (0=disable,1=enable) 0
|
||||
// 2 I2_WTM FIFO wtrmrk int on DRDY/INT2 (0=dsbl,1=enbl) 0
|
||||
// 1 I2_ORun FIFO overrun int on DRDY/INT2 (0=dsbl,1=enbl) 0
|
||||
// 0 I2_Empty FIFI empty int on DRDY/INT2 (0=dsbl,1=enbl) 0
|
||||
CTRL_REG3 uint8 = 0x22
|
||||
// CTRL_REG4 (0x23)
|
||||
// ====================================================================
|
||||
// BIT Symbol Description Default
|
||||
// --- ------ --------------------------------------------- -------
|
||||
// 7 BDU Block Data Update (0=continuous, 1=LSB/MSB) 0
|
||||
// 6 BLE Big/Little-Endian (0=Data LSB, 1=Data MSB) 0
|
||||
// 5-4 FS1/0 Full scale selection 00
|
||||
// 00 = 250 dps
|
||||
// 01 = 500 dps
|
||||
// 10 = 2000 dps
|
||||
// 11 = 2000 dps
|
||||
// 0 SIM SPI Mode (0=4-wire, 1=3-wire) 0
|
||||
CTRL_REG4 uint8 = 0x23
|
||||
// CTRL_REG5 (0x24)
|
||||
// ====================================================================
|
||||
// BIT Symbol Description Default
|
||||
// --- ------ --------------------------------------------- -------
|
||||
// 7 BOOT Reboot memory content (0=normal, 1=reboot) 0
|
||||
// 6 FIFO_EN FIFO enable (0=FIFO disable, 1=enable) 0
|
||||
// 4 HPen High-pass filter enable (0=disable,1=enable) 0
|
||||
// 3-2 INT1_SEL INT1 Selection config 00
|
||||
// 1-0 OUT_SEL Out selection config 00
|
||||
CTRL_REG5 uint8 = 0x24
|
||||
REFERENCE uint8 = 0x25
|
||||
OUT_TEMP uint8 = 0x26
|
||||
STATUS_REG uint8 = 0x27
|
||||
OUT_X_L uint8 = 0x28
|
||||
OUT_X_H uint8 = 0x29
|
||||
OUT_Y_L uint8 = 0x2A
|
||||
OUT_Y_H uint8 = 0x2B
|
||||
OUT_Z_L uint8 = 0x2C
|
||||
OUT_Z_H uint8 = 0x2D
|
||||
FIFO_CTRL_REG uint8 = 0x2E
|
||||
FIFO_SRC_REG uint8 = 0x2F
|
||||
INT1_CFG uint8 = 0x30
|
||||
INT1_SRC uint8 = 0x31
|
||||
INT1_TSH_XH uint8 = 0x32
|
||||
INT1_TSH_XL uint8 = 0x33
|
||||
INT1_TSH_YH uint8 = 0x34
|
||||
INT1_TSH_YL uint8 = 0x35
|
||||
INT1_TSH_ZH uint8 = 0x36
|
||||
INT1_TSH_ZL uint8 = 0x37
|
||||
INT1_DURATION uint8 = 0x38
|
||||
)
|
||||
+14
-12
@@ -14,18 +14,12 @@ type Device struct {
|
||||
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})
|
||||
// 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}
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in milli pascals (mPa).
|
||||
@@ -42,6 +36,14 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
return int32(pValue * 1000), nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
d.waitForOneShot()
|
||||
|
||||
@@ -5,10 +5,8 @@ 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}
|
||||
// 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})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user