mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
Compare commits
187 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90a13a697b | |||
| d632eb888f | |||
| f6761a9079 | |||
| 51c3aa271b | |||
| 520234e9f8 | |||
| 334ed57373 | |||
| 3637033fec | |||
| 233866443c | |||
| 65fd7aa1a1 | |||
| 82e9e4a7f3 | |||
| 76ff632134 | |||
| cd2694e85f | |||
| 734adb6df8 | |||
| 2492fcb322 | |||
| 4f82c231cb | |||
| 2c9a05a413 | |||
| a89a26112e | |||
| bd42656644 | |||
| 94729a4f7d | |||
| 050cf4dbbc | |||
| 49c8810432 | |||
| 4b38841f71 | |||
| 3fe3fc64e4 | |||
| 0565a15b17 | |||
| fad9d12e0b | |||
| f2e5278965 | |||
| 259593e608 | |||
| 7a2b1b8c90 | |||
| cad03a7d4e | |||
| 98f5396625 | |||
| 3b16972ed8 | |||
| b35496dd1b | |||
| ad6be40966 | |||
| b3af3f594e | |||
| 9a3bfd4826 | |||
| 1ba9ba3143 | |||
| feb1c63656 | |||
| 0691ed5205 | |||
| e70beede1c | |||
| 92673d996d | |||
| 374e2dfe1d | |||
| b35aab6d61 | |||
| 358501fc47 | |||
| a0119ffc6f | |||
| 58106b5942 | |||
| 2537c69b0f | |||
| 633f19c4ac | |||
| 6a4cd9d8e7 | |||
| 8a4a0ff017 | |||
| 1cbf1a6f3d | |||
| 001bdb43ba | |||
| f7ae6fac6d | |||
| a575b2a4ed | |||
| 0bc3702dd0 | |||
| b53a8a17e7 | |||
| 5e117c162c | |||
| 24dfd8795a | |||
| a748451cab | |||
| a811483fd4 | |||
| 7b565e8cb0 | |||
| 5645eb3f91 | |||
| 6b914f7af7 | |||
| 5a02fe068b | |||
| 5ecefde991 | |||
| 9adbde99a2 | |||
| a09ec31e7a | |||
| d07ad40373 | |||
| aa17ffd1cb | |||
| ce03bebc34 | |||
| dfd652ca1f | |||
| c765ef3970 | |||
| 428db3cd12 | |||
| d7f619ca21 | |||
| d1ace44754 | |||
| 6b58fdc95a | |||
| bd2530abee | |||
| 3bcde1485c | |||
| 351700e48d | |||
| cbcb62af01 | |||
| 19bb773e5b | |||
| 69cc0b22c4 | |||
| 2a48b5c25d | |||
| e6a822f68b | |||
| f65bce6d36 | |||
| 67b8a341a6 | |||
| b869d27170 | |||
| 107932a201 | |||
| d2db0c28e2 | |||
| 761bcfc4db | |||
| 91dadd5535 | |||
| f7dc106fc8 | |||
| df343190c2 | |||
| 6bc466f79b | |||
| 23776bf906 | |||
| e77e9249cd | |||
| 1345bc2161 | |||
| ab795cc186 | |||
| 36213a1cdc | |||
| 963c903d71 | |||
| 2cec480fb8 | |||
| 68da7f437b | |||
| d0632fccfa | |||
| 2c0a74df4d | |||
| c6228a0677 | |||
| 33ec7fc98f | |||
| 75c15d5d0b | |||
| e1deb45aac | |||
| d1cafbc2b2 | |||
| 0b6bfda8cf | |||
| 84408279de | |||
| de1e6a626a | |||
| 7531c9d334 | |||
| ee44900c25 | |||
| b9a70aeb6f | |||
| cad0a320b7 | |||
| a53a39922b | |||
| 41d6a4c3fa | |||
| 60ba0e3b30 | |||
| 2b5f43029c | |||
| a771641339 | |||
| 5741ceb9d1 | |||
| 27ef18930e | |||
| e9a6d96ddd | |||
| 9a7cb1a22f | |||
| d170ec8d81 | |||
| 0fc2d28ca8 | |||
| ef34c13cc1 | |||
| c64d7920dc | |||
| 008157b6c9 | |||
| 0ed9683a52 | |||
| 01acd977f3 | |||
| 231ec57202 | |||
| 5d3ad4ba52 | |||
| 8cb226938b | |||
| ce5e443084 | |||
| edf9ba92be | |||
| c1c05cbef7 | |||
| c338348d2b | |||
| b6aa674b2a | |||
| cc7079b0cd | |||
| 42a907035b | |||
| 46c9ba9595 | |||
| df64ce8f50 | |||
| e376785596 | |||
| 4c98d0bc34 | |||
| 65f8299153 | |||
| a689aef543 | |||
| 7cd7df7bb8 | |||
| 705f474897 | |||
| ce9c93f228 | |||
| db02cbb8a4 | |||
| a07b20f2f9 | |||
| 4ad210060f | |||
| 2ae950e96d | |||
| dd34b83e9f | |||
| ce81b66fe2 | |||
| b1ae52d1b9 | |||
| 794a9c202f | |||
| 38f97a8b45 | |||
| 35a146d60e | |||
| 4f82c06df9 | |||
| af4efceac1 | |||
| 5df96c8138 | |||
| 88aeec9f69 | |||
| 06b2023b25 | |||
| 8163dec7c3 | |||
| 5a75c9c403 | |||
| 75b8a75b4b | |||
| 857e45f18d | |||
| 9130e61c55 | |||
| 68963a1b42 | |||
| 74c9ff4c76 | |||
| de27fae9a2 | |||
| 5ebc7cb09e | |||
| 07ca36ac5a | |||
| 39f44ef478 | |||
| 61874ea928 | |||
| f5e81e6a01 | |||
| 511a3282b7 | |||
| 1d09194bbc | |||
| 941ea4e28b | |||
| 21ba9392e2 | |||
| 7967e82fed | |||
| 91539d9ef8 | |||
| c3f3af5ffa | |||
| 41694085a1 | |||
| fd9b1ba89b |
@@ -6,13 +6,15 @@ jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: tinygo/tinygo-dev
|
||||
working_directory: /usr/local/go/src/tinygo.org/x/drivers
|
||||
steps:
|
||||
- checkout
|
||||
- run: tinygo version
|
||||
- run:
|
||||
name: "Enforce Go Formatted Code"
|
||||
command: make fmt-check
|
||||
- run:
|
||||
name: "Run unit tests"
|
||||
command: make unit-test
|
||||
- run:
|
||||
name: "Run build and smoke tests"
|
||||
command: make smoke-test
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
build
|
||||
.vscode/
|
||||
|
||||
+185
@@ -1,3 +1,188 @@
|
||||
0.18.0
|
||||
---
|
||||
- **new devices**
|
||||
- apds9960: add support for APDS-9960 Digital Proximity sensor
|
||||
- axp192: add support for AXP192 single Cell Li-Battery and power system management IC
|
||||
- hts221: add support for HTS221 capacitive digital sensor for relative humidity and temperature
|
||||
- i2csoft: add support for software I2C
|
||||
- image: add support for image/jpeg and image/png
|
||||
- lps22hb: add support for LPS22HB MEMS nano pressure sensor
|
||||
- lsm6dox: add support for lsm6dox accelerometer
|
||||
- lsm9ds1: add support for lsm9ds1 accelerometer
|
||||
- **enhancements**
|
||||
- ili9341: change to use drivers.SPI interface
|
||||
- **ws2812**
|
||||
- generate assembly instead of handwriting it
|
||||
- improve timings to be compatible with the WS2811
|
||||
- add support for 168MHz (e.g. Adafruit Feather STM32F405)
|
||||
- add support for RISC-V
|
||||
- wifinina: control nina pins, for example leds
|
||||
- **docs**
|
||||
- rtl8720dn: examples for tcpclient, udpstation, mqtt, and webserver
|
||||
- **wifinina**
|
||||
- nina-fw update docs
|
||||
- examples/wifinina/http-get
|
||||
- ili9341: refactor examples
|
||||
- Fix broken link for SHT3x datasheet
|
||||
- **core**
|
||||
- all: use build directives for both Go1.17 and earlier versions
|
||||
- **bugfixes**
|
||||
- net: fix raddr of tcp conn
|
||||
- mcp3008: fix bitshift bug
|
||||
|
||||
0.17.1
|
||||
---
|
||||
- To correct an error in the release process. Same as 0.17.0.
|
||||
|
||||
0.17.0
|
||||
---
|
||||
- **new devices**
|
||||
- rtl8720dn: add support for rtl8720dn
|
||||
- sdcard: add support for spi sdcard driver, along with fatfs
|
||||
- **enhancements**
|
||||
- apa102: use 4-byte buffer to improve speed
|
||||
- bmi160: avoid heap allocations
|
||||
- ili9341: add standard SPI driver
|
||||
- wifinina
|
||||
- avoid fmt package
|
||||
- Fix RSSI command for WiFiNINA + Print current SSID + Wait for correct time before printing it out + Cleanup
|
||||
- ws2812
|
||||
- rename the pin to ws2812
|
||||
- add tag for nrf52833
|
||||
- Disable interrupts before sending ws2812 data
|
||||
- add support for qtpy and atsame5x
|
||||
- **core**
|
||||
- modules: switch to use tinygo-org version of tinyfs package
|
||||
- all: use machine.Serial as the default output
|
||||
|
||||
0.16.0
|
||||
---
|
||||
- **new devices**
|
||||
- aht20: add device
|
||||
- ina260: add new i2c device
|
||||
- keypad: add 4x4 keypad driver (#226)
|
||||
- max7219: add driver support
|
||||
- mcp2515: add support for mcp2515 CAN device
|
||||
- p1am: support the P1AM-100 hardware watchdog
|
||||
- pcf8563: add support for pcf8563 real time clock
|
||||
- servo: add driver using PWM
|
||||
- tm1637: add support for tm1637 7-segment LED
|
||||
- tone: add package for producing tones using the PWM interface
|
||||
- **enhancements**
|
||||
- pwm: update drivers with PWM to use new interface
|
||||
- wifinina: Make TLS work over WiFiNINA Verified on Arduino Nano33 IoT and nina fw v1.4.5
|
||||
- ssd1306: Enable reset screen for SSD1306 via I2C
|
||||
- st7789: add scrolling functions to match st7735
|
||||
- **bugfixes**
|
||||
- wifinina:
|
||||
- fix getMACAddress and getTime
|
||||
- fix println + cleanup
|
||||
- remove debug flag and remove unnecessary padding call
|
||||
- fix padding and implement missing functions
|
||||
- flash: fix EraseBlocks method which is erasing sectors instead
|
||||
- **core**
|
||||
- all: use interfaces for UART objects
|
||||
- all: do not take the pointer of an I2C object
|
||||
- adc: update drivers with ADC to use new config struct
|
||||
- **testing**
|
||||
- tester:
|
||||
- add a mock for command-oriented i2c devices
|
||||
- add 16-bit register mock device
|
||||
|
||||
- **docs**
|
||||
- ssd1306: example of ssd1306 with 128x64 display over I2C
|
||||
- wifinina:
|
||||
- add information about Adafruit boards with ESP32 wifi coprocessors, and modify examples to remove code that was both not being used, and also prevented many Adafruit boards from being able to be targeted by the examples
|
||||
- update docs to simplify the nina-fw update process
|
||||
- example that connects to AP and prints ip addresses, time and mac
|
||||
- p1am: documentation and example program
|
||||
- add missing new drivers added since last release
|
||||
|
||||
0.15.0
|
||||
---
|
||||
- **new devices**
|
||||
- dht: add DHTXX thermometer
|
||||
- mcp23017: new driver for MCP23017 (I2C port expander)
|
||||
- bmp388: Add bmp388 support (#219)
|
||||
- **enhancements**
|
||||
- hd44780: add a mode to work with boards where the RW pin is grounded
|
||||
- st7789: add scrolling functions to match st7735
|
||||
- microbitmatrix: matrix now working on microbit v2
|
||||
- ds1307: Better interface "ReadTime" instead of "Time"
|
||||
- ws2812: make AVR support more robust
|
||||
- **bugfixes**
|
||||
- all: fix main package in examples
|
||||
- **core**
|
||||
- adc: update all drivers with ADC to use new config struct
|
||||
- spi: remove machine.SPI and replace with drivers.SPI interface for almost all SPI drivers
|
||||
- **testing**
|
||||
- test: run unit tests against i2c drivers and any spi drivers without direct gpio
|
||||
- **docs**
|
||||
- st7789: correct errors on various godoc comments
|
||||
|
||||
0.14.0
|
||||
---
|
||||
- **new devices**
|
||||
- lis2mdl: add LIS2MDL magnetometer (#187)
|
||||
- waveshare: add Waveshare 4.2in B/W e-paper driver (#183)
|
||||
- **enhancements**
|
||||
- adt7410: add connection test and for that matter connection method
|
||||
- gps
|
||||
- add speed and heading to fix, as parsed from RMC NMEA sentence
|
||||
- improvements and bugfixes (#186)
|
||||
- ili9341
|
||||
- add support for setting framerate, vsync pause, and reading scanline data.
|
||||
- renamed NewSpi() to NewSPI() in accordance with Go naming conventions
|
||||
- ws2812
|
||||
- add support for ESP8266
|
||||
- add support for ESP32
|
||||
- **bugfixes**
|
||||
- ili9341
|
||||
- rix setWindow bug, add CS pin for Clue compatibility. (#180)
|
||||
- bugfix for RAMWR bug
|
||||
- lis2mdl: turn on read mode on every read, to ensure that magnetometer data is updated
|
||||
- **core**
|
||||
- i2c
|
||||
- switch all i2c drivers definitions to use i2c bus interface type instead of machine package concrete type
|
||||
- correct interface definition for I2C Tx function
|
||||
- **testing**
|
||||
- fix smoke-test unless avr-gcc installed
|
||||
- add very basic mock structs for testing i2c devices, based on work done by @rogpeppe
|
||||
- improve API surface and implement one more test function in lis2mdl driver
|
||||
- **docs**
|
||||
- replace README badge for godocs with pkgdocs
|
||||
|
||||
0.13.0
|
||||
---
|
||||
- **new devices**
|
||||
- bmi160: add initial support
|
||||
- bmp280: added support for the Bosch BMP280 temperature and pressure sensor. (#158)
|
||||
- lsm303agr: add lsm303agr (#162)
|
||||
- ssd1351: add SSD1351 OLED display driver (#146)
|
||||
- **enhancements**
|
||||
- hd44780: add Hd44780i2c driver (#173)
|
||||
- ili9341
|
||||
- add ILI9341 TFT driver (SPI) for ATSAMD2x (#174)
|
||||
- cache address window to prevent sending unnecessary commands (#171)
|
||||
- ILI9341 TFT driver (SPI) (#153)
|
||||
- improve performance of ILI9341 on ATSAMD5X
|
||||
- ST77xx: fix DrawFastHLine for ST77xx, SSD1331 and SSD1351 DrawFastHLine uses FillRectangle(x,y,width,height,c), so height must be 1 to draw a horizontal line
|
||||
- tmp102: add Connected func to check for device
|
||||
- wifinina: added UDP support
|
||||
- ws2812: update ws2812_avr_16m.go
|
||||
- **bugfixes**
|
||||
- apa102: avoid creating garbage
|
||||
- bmp180: fix temperature type conversion
|
||||
- **core**
|
||||
- all
|
||||
- added custom import path (#161)
|
||||
- changeover to eliminate all direct use of master/slave terminology
|
||||
- build: try vendor in working directory to match expected module path
|
||||
- ci: support Go modules
|
||||
- modules: update go version and dependency
|
||||
- **docs**
|
||||
- docs: reorder to correct alpha and adjust count of supported drivers
|
||||
|
||||
0.12.0
|
||||
---
|
||||
- **new devices**
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ Please first open a Github issue. We want to help, and also make sure that there
|
||||
|
||||
## How to use our Github repository
|
||||
|
||||
The `master` branch of this repo will always have the latest released version of the TinyGo drivers. All of the active development work for the next release will take place in the `dev` branch. The TinyGo drivers will use semantic versioning and will create a tag/release for each release.
|
||||
The `release` branch of this repo will always have the latest released version of the TinyGo drivers. All of the active development work for the next release will take place in the `dev` branch. The TinyGo drivers will use semantic versioning and will create a tag/release for each release.
|
||||
|
||||
Here is how to contribute back some code or documentation:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2020 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2021 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
clean:
|
||||
@rm -rf build
|
||||
|
||||
FMT_PATHS = ./*.go ./examples/**/*.go
|
||||
FMT_PATHS = ./
|
||||
|
||||
fmt-check:
|
||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||
@@ -17,6 +17,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
|
||||
@@ -25,8 +27,14 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/blinkm/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmi160/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp180/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp280/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bmp388/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/sram/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/time/main.go
|
||||
@@ -55,30 +63,56 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/text/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/hd44780i2c/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/hts221/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hub75/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic/main.go
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/scroll/main.go
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/basic
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/pyportal_boing
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/scroll
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/scroll
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/slideshow
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017-multiple/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp2515/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mpu6050/main.go
|
||||
@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=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
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
||||
@@ -95,6 +129,10 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/thermistor/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-bluefruit ./examples/tone
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/tm1637/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/fourwire/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/pyportal_touchpaint/main.go
|
||||
@@ -105,14 +143,24 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd4in2/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/ntpclient/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/udpstation/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/tcpclient/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/webclient/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812
|
||||
@md5sum ./build/test.hex
|
||||
ifneq ($(AVR), 0)
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/ws2812
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=digispark ./examples/ws2812
|
||||
@md5sum ./build/test.hex
|
||||
endif
|
||||
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bme280/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/microphone/main.go
|
||||
@@ -131,5 +179,51 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-f103rb ./examples/shiftregister/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=hifive1b ./examples/ssd1351/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/max72xx/main.go
|
||||
@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=xiao ./examples/pcf8563/alarm/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/time/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/tinyfs/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webclient/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webserver/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/mqttsub/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
|
||||
@md5sum ./build/test.hex
|
||||
|
||||
test: clean fmt-check smoke-test
|
||||
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
|
||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||
|
||||
unit-test:
|
||||
@go test -v $(addprefix ./,$(TESTS))
|
||||
|
||||
test: clean fmt-check unit-test smoke-test
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# TinyGo Drivers
|
||||
|
||||
[](https://godoc.org/tinygo.org/x/drivers) [](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
|
||||
[](https://pkg.go.dev/tinygo.org/x/drivers) [](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
|
||||
|
||||
|
||||
This package provides a collection of hardware drivers for devices that can be used together with [TinyGo](https://tinygo.org).
|
||||
This package provides a collection of hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
|
||||
|
||||
## Installing
|
||||
|
||||
@@ -52,57 +52,84 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 48 devices are supported.
|
||||
The following 74 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|----------|-------------|
|
||||
| [ADT7410 I2C Temperature Sensor](https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf) | I2C |
|
||||
| [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C |
|
||||
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
|
||||
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
|
||||
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
|
||||
| [APDS9960 Digital proximity, ambient light, RGB and gesture sensor](https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf) | I2C |
|
||||
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
|
||||
| [AXP192 single Cell Li-Battery and Power System Management](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf) | I2C |
|
||||
| [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO |
|
||||
| [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C |
|
||||
| [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C |
|
||||
| [BME280 humidity/pressure sensor](https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf) | I2C |
|
||||
| [BMI160 accelerometer/gyroscope](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi160-ds000.pdf) | SPI |
|
||||
| [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C |
|
||||
| [BMP280 temperature/barometer](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf) | I2C |
|
||||
| [BMP388 pressure sensor](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf) | I2C |
|
||||
| [Buzzer](https://en.wikipedia.org/wiki/Buzzer#Piezoelectric) | GPIO |
|
||||
| [DHTXX thermometer and humidity sensor](https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf) | GPIO |
|
||||
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
|
||||
| [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 |
|
||||
| [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 |
|
||||
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
|
||||
| [HTS221 digital humidity and temperature sensor](https://www.st.com/resource/en/datasheet/hts221.pdf) | I2C |
|
||||
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
|
||||
| [software I2C driver](https://www.ti.com/lit/an/slva704/slva704.pdf) | GPIO |
|
||||
| [ILI9341 TFT color display](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) | SPI |
|
||||
| [INA260 Volt/Amp/Power meter](https://www.ti.com/lit/ds/symlink/ina260.pdf) | I2C |
|
||||
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
|
||||
| [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 |
|
||||
| [LIS2MDL magnetometer](https://www.st.com/resource/en/datasheet/lis2mdl.pdf) | I2C |
|
||||
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
|
||||
| [LPS22HB MEMS nano pressure sensor](https://www.st.com/resource/en/datasheet/dm00140895.pdf) | I2C |
|
||||
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C |
|
||||
| [LSM6DSOX accelerometer](https://www.st.com/resource/en/datasheet/lsm6dsox.pdf) | I2C |
|
||||
| [LSM303AGR accelerometer](https://www.st.com/resource/en/datasheet/lsm303agr.pdf) | I2C |
|
||||
| [LSM9DS1 accelerometer](https://www.st.com/resource/en/datasheet/lsm9ds1.pdf) | I2C |
|
||||
| [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C |
|
||||
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
|
||||
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
|
||||
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
||||
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
||||
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
|
||||
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
|
||||
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
||||
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
|
||||
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
||||
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
|
||||
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
|
||||
| [RTL8720DN 2.4G/5G Dual Bands Wireless and BLE5.0](https://www.seeedstudio.com/Realtek8720DN-2-4G-5G-Dual-Bands-Wireless-and-BLE5-0-Combo-Module-p-4442.html) | UART |
|
||||
| [Semihosting](https://wiki.segger.com/Semihosting) | Debug |
|
||||
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
|
||||
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
|
||||
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
||||
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
|
||||
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
|
||||
| [SSD1351 OLED display](https://download.mikroe.com/documents/datasheets/ssd1351-revision-1.3.pdf) | SPI |
|
||||
| [ST7735 TFT color display](https://www.crystalfontz.com/controllers/Sitronix/ST7735R/319/) | SPI |
|
||||
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
|
||||
| [Stepper motor "Easystepper" controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
|
||||
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
|
||||
| [TM1637 7-segment LED display](https://www.mcielectronics.cl/website_MCI/static/documents/Datasheet_TM1637.pdf) | I2C |
|
||||
| [TMP102 I2C Temperature Sensor](https://download.mikroe.com/documents/datasheets/tmp102-data-sheet.pdf) | I2C |
|
||||
| [VEML6070 UV light sensor](https://www.vishay.com/docs/84277/veml6070.pdf) | I2C |
|
||||
| [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C |
|
||||
| [Waveshare 2.13" (B & C) e-paper display](https://www.waveshare.com/w/upload/d/d3/2.13inch-e-paper-b-Specification.pdf) | SPI |
|
||||
| [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 |
|
||||
|
||||
## Contributing
|
||||
|
||||
+30
-28
@@ -1,8 +1,13 @@
|
||||
package adt7410
|
||||
// Package adt7410 provides a driver for the adt7410 I2C Temperature Sensor.
|
||||
//
|
||||
// Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf
|
||||
//
|
||||
package adt7410 // import "tinygo.org/x/drivers/adt7410"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type Error uint8
|
||||
@@ -21,40 +26,37 @@ func (e Error) Error() string {
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
bus *machine.I2C
|
||||
buf []byte
|
||||
addr uint8
|
||||
bus drivers.I2C
|
||||
buf []byte
|
||||
Address uint8
|
||||
}
|
||||
|
||||
// New returns ADT7410 device for the provided I2C bus and address. The ADT7410
|
||||
// has a default address of 0x48 (1001000). The last 2 bits of the address
|
||||
// New returns ADT7410 device for the provided I2C bus using default address.
|
||||
// of 0x48 (1001000). To use multiple ADT7410 devices, the last 2 bits of the address
|
||||
// can be set using by connecting to the A1 and A0 pins to VDD or GND (for a
|
||||
// total of up to 4 devices on a I2C bus). Also note that 10k pullups are
|
||||
// recommended for the SDA and SCL lines.
|
||||
func New(i2c *machine.I2C, addressBits uint8) *Device {
|
||||
func New(i2c drivers.I2C) *Device {
|
||||
return &Device{
|
||||
bus: i2c,
|
||||
buf: make([]byte, 2),
|
||||
addr: Address | (addressBits & 0x3),
|
||||
bus: i2c,
|
||||
buf: make([]byte, 2),
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *Device) Configure() (err error) {
|
||||
|
||||
// verify the chip ID
|
||||
// TODO: According to datasheet, the check below should work; however
|
||||
// this does not seem to be working right, but is not exactly
|
||||
// necessary, so can revisit later to see if there is a bug
|
||||
//id := dev.ReadByte(RegID) & 0xF8
|
||||
//if id != 0xC8 {
|
||||
// err = ErrInvalidID
|
||||
//}
|
||||
|
||||
// Configure the ADT7410 device.
|
||||
func (d *Device) Configure() (err error) {
|
||||
// reset the chip
|
||||
dev.writeByte(RegReset, 0xFF)
|
||||
d.writeByte(RegReset, 0xFF)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return
|
||||
}
|
||||
|
||||
// Connected returns whether sensor has been found.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(uint8(d.Address), RegID, data)
|
||||
return data[0]&0xF8 == 0xC8
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
||||
@@ -62,13 +64,13 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
return (int32(d.readUint16(RegTempValueMSB)) * 1000) / 128, nil
|
||||
}
|
||||
|
||||
// ReadTempC returns the value in the temperature value register, in Celcius
|
||||
// ReadTempC returns the value in the temperature value register, in Celsius.
|
||||
func (d *Device) ReadTempC() float32 {
|
||||
t := d.readUint16(RegTempValueMSB)
|
||||
return float32(int(t)) / 128.0
|
||||
}
|
||||
|
||||
// ReadTempF returns the value in the temperature value register, in Fahrenheit
|
||||
// ReadTempF returns the value in the temperature value register, in Fahrenheit.
|
||||
func (d *Device) ReadTempF() float32 {
|
||||
return d.ReadTempC()*1.8 + 32.0
|
||||
}
|
||||
@@ -76,15 +78,15 @@ func (d *Device) ReadTempF() float32 {
|
||||
func (d *Device) writeByte(reg uint8, data byte) {
|
||||
d.buf[0] = reg
|
||||
d.buf[1] = data
|
||||
d.bus.Tx(uint16(d.addr), d.buf, nil)
|
||||
d.bus.Tx(uint16(d.Address), d.buf, nil)
|
||||
}
|
||||
|
||||
func (d *Device) readByte(reg uint8) byte {
|
||||
d.bus.ReadRegister(d.addr, reg, d.buf)
|
||||
d.bus.ReadRegister(d.Address, reg, d.buf)
|
||||
return d.buf[0]
|
||||
}
|
||||
|
||||
func (d *Device) readUint16(reg uint8) uint16 {
|
||||
d.bus.ReadRegister(d.addr, reg, d.buf)
|
||||
d.bus.ReadRegister(d.Address, reg, d.buf)
|
||||
return uint16(d.buf[0])<<8 | uint16(d.buf[1])
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package adt7410
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"tinygo.org/x/drivers/tester"
|
||||
)
|
||||
|
||||
func TestDefaultI2CAddress(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
dev := New(bus)
|
||||
c.Assert(dev.Address, qt.Equals, uint8(Address))
|
||||
}
|
||||
|
||||
func TestWhoAmI(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice(c, Address)
|
||||
copy(fake.Registers[:], defaultRegisters())
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
c.Assert(dev.Connected(), qt.Equals, true)
|
||||
|
||||
fake.Registers[RegID] = 0x99
|
||||
c.Assert(dev.Connected(), qt.Equals, false)
|
||||
}
|
||||
|
||||
// defaultRegisters returns the default values for all of the device's registers.
|
||||
// see table 22 on page 27 of the datasheet.
|
||||
func defaultRegisters() []uint8 {
|
||||
return []uint8{
|
||||
RegTempValueMSB: 0,
|
||||
RegTempValueLSB: 0,
|
||||
RegStatus: 0,
|
||||
RegConfig: 0,
|
||||
RegTHIGHMsbReg: 0x20,
|
||||
RegTHIGHLsbReg: 0,
|
||||
RegTLOWMsbReg: 0x05,
|
||||
RegTLOWLsbReg: 0,
|
||||
RegTCRITMsbReg: 0x49,
|
||||
RegTCRITLsbReg: 0x80,
|
||||
RegTHYSTReg: 0x05,
|
||||
RegID: 0xC8,
|
||||
RegReset: 0,
|
||||
}
|
||||
}
|
||||
+48
-2
@@ -1,8 +1,33 @@
|
||||
package adt7410
|
||||
|
||||
// 0x00 Temperature value most significant byte 0x00
|
||||
// 0x01 Temperature value least significant byte 0x00
|
||||
// 0x02 Status 0x00
|
||||
// 0x03 Configuration 0x00
|
||||
// 0x04 THIGH setpoint most significant byte 0x20 (64°C)
|
||||
// 0x05 THIGH setpoint least significant byte 0x00 (64°C)
|
||||
// 0x06 TLOW setpoint most significant byte 0x05 (10°C)
|
||||
// 0x07 TLOW setpoint least significant byte 0x00 (10°C)
|
||||
// 0x08 TCRIT setpoint most significant byte 0x49 (147°C)
|
||||
// 0x09 TCRIT setpoint least significant byte 0x80 (147°C)
|
||||
// 0x0A THYST setpoint 0x05 (5°C)
|
||||
// 0x0B ID 0xCX
|
||||
// 0x0C Reserved 0xXX
|
||||
// 0x0D Reserved 0xXX
|
||||
// 0x2E Reserved 0xXX
|
||||
// 0x2F Software reset 0xXX
|
||||
|
||||
const (
|
||||
// Default I2C address
|
||||
// Address is default I2C address.
|
||||
Address = 0x48
|
||||
// Address1 is for first device, aka the default.
|
||||
Address1 = Address
|
||||
// Address2 is for second device.
|
||||
Address2 = 0x49
|
||||
// Address3 is for third device.
|
||||
Address3 = 0x4A
|
||||
// Address4 is for fourth device.
|
||||
Address4 = 0x4B
|
||||
|
||||
// Temperature Value MSB Register
|
||||
RegTempValueMSB = 0x0
|
||||
@@ -16,7 +41,28 @@ const (
|
||||
// Config Register
|
||||
RegConfig = 0x3
|
||||
|
||||
// ID Register
|
||||
// THIGH setpoint most significant byte 0x20 (64°C)
|
||||
RegTHIGHMsbReg = 0x4
|
||||
|
||||
// THIGH setpoint least significant byte 0x00 (64°C)
|
||||
RegTHIGHLsbReg = 0x5
|
||||
|
||||
// TLOW setpoint most significant byte 0x05 (10°C)
|
||||
RegTLOWMsbReg = 0x6
|
||||
|
||||
// TLOW setpoint least significant byte 0x00 (10°C)
|
||||
RegTLOWLsbReg = 0x7
|
||||
|
||||
// TCRIT setpoint most significant byte 0x49 (147°C)
|
||||
RegTCRITMsbReg = 0x8
|
||||
|
||||
// TCRIT setpoint least significant byte 0x80 (147°C)
|
||||
RegTCRITLsbReg = 0x9
|
||||
|
||||
// THYST setpoint 0x05 (5°C)
|
||||
RegTHYSTReg = 0xA
|
||||
|
||||
// ID Register (0xCx)
|
||||
RegID = 0x0B
|
||||
|
||||
// Software Reset Register
|
||||
|
||||
+3
-5
@@ -6,9 +6,7 @@
|
||||
//
|
||||
package adxl345 // import "tinygo.org/x/drivers/adxl345"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
)
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
type Range uint8
|
||||
type Rate uint8
|
||||
@@ -40,7 +38,7 @@ type bwRate struct {
|
||||
|
||||
// Device wraps an I2C connection to a ADXL345 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
powerCtl powerCtl
|
||||
dataFormat dataFormat
|
||||
@@ -52,7 +50,7 @@ type Device struct {
|
||||
//
|
||||
// This function only creates the Device object, it does not init the device.
|
||||
// To do that you must call the Configure() method on the Device before using it.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
powerCtl: powerCtl{
|
||||
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package aht20
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to an AHT20 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
humidity uint32
|
||||
temp uint32
|
||||
}
|
||||
|
||||
// New creates a new AHT20 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: Address,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the device
|
||||
func (d *Device) Configure() {
|
||||
// Check initialization state
|
||||
status := d.Status()
|
||||
if status&0x08 == 1 {
|
||||
// Device is initialized
|
||||
return
|
||||
}
|
||||
|
||||
// Force initialization
|
||||
d.bus.Tx(d.Address, []byte{CMD_INITIALIZE, 0x08, 0x00}, nil)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Reset the device
|
||||
func (d *Device) Reset() {
|
||||
d.bus.Tx(d.Address, []byte{CMD_SOFTRESET}, nil)
|
||||
}
|
||||
|
||||
// Status of the device
|
||||
func (d *Device) Status() byte {
|
||||
data := []byte{0}
|
||||
|
||||
d.bus.Tx(d.Address, []byte{CMD_STATUS}, data)
|
||||
|
||||
return data[0]
|
||||
}
|
||||
|
||||
// Read the temperature and humidity
|
||||
//
|
||||
// The actual temperature and humidity are stored
|
||||
// and can be accessed using `Temp` and `Humidity`.
|
||||
func (d *Device) Read() error {
|
||||
d.bus.Tx(d.Address, []byte{CMD_TRIGGER, 0x33, 0x00}, nil)
|
||||
|
||||
data := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
for retry := 0; retry < 3; retry++ {
|
||||
time.Sleep(80 * time.Millisecond)
|
||||
err := d.bus.Tx(d.Address, nil, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If measurement complete, store values
|
||||
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
|
||||
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
|
||||
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ErrTimeout
|
||||
}
|
||||
|
||||
func (d *Device) RawHumidity() uint32 {
|
||||
return d.humidity
|
||||
}
|
||||
|
||||
func (d *Device) RawTemp() uint32 {
|
||||
return d.temp
|
||||
}
|
||||
|
||||
func (d *Device) RelHumidity() float32 {
|
||||
return (float32(d.humidity) * 100) / 0x100000
|
||||
}
|
||||
|
||||
func (d *Device) DeciRelHumidity() int32 {
|
||||
return (int32(d.humidity) * 1000) / 0x100000
|
||||
}
|
||||
|
||||
// Temperature in degrees celsius
|
||||
func (d *Device) Celsius() float32 {
|
||||
return (float32(d.temp*200.0) / 0x100000) - 50
|
||||
}
|
||||
|
||||
// Temperature in mutiples of one tenth of a degree celsius
|
||||
//
|
||||
// Using this method avoids floating point calculations.
|
||||
func (d *Device) DeciCelsius() int32 {
|
||||
return ((int32(d.temp) * 2000) / 0x100000) - 500
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package aht20
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"tinygo.org/x/drivers/tester"
|
||||
)
|
||||
|
||||
func TestDefaultI2CAddress(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
dev := New(bus)
|
||||
c.Assert(uint8(dev.Address), qt.Equals, uint8(Address))
|
||||
}
|
||||
|
||||
func TestInitialization(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fdev := tester.NewI2CDeviceCmd(c, Address)
|
||||
fdev.Commands = defaultCommands()
|
||||
bus.AddDevice(fdev)
|
||||
|
||||
// Set status to uninitialized to force initialization
|
||||
fdev.Commands[CMD_STATUS].Response[0] = 0x0C
|
||||
|
||||
dev := New(bus)
|
||||
dev.Configure()
|
||||
|
||||
// Check initialization command invoked
|
||||
c.Assert(fdev.Commands[CMD_INITIALIZE].Invocations > 0, qt.Equals, true)
|
||||
}
|
||||
|
||||
func TestRead(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fdev := tester.NewI2CDeviceCmd(c, Address)
|
||||
fdev.Commands = defaultCommands()
|
||||
bus.AddDevice(fdev)
|
||||
|
||||
dev := New(bus)
|
||||
dev.Read()
|
||||
|
||||
// Should be 25deg (250 decidegrees)
|
||||
c.Assert(dev.DeciCelsius(), qt.Equals, int32(250))
|
||||
|
||||
// Should be 36.3% (363 decipercent)
|
||||
c.Assert(dev.DeciRelHumidity(), qt.Equals, int32(363))
|
||||
}
|
||||
|
||||
func defaultCommands() map[uint8]*tester.Cmd {
|
||||
return map[uint8]*tester.Cmd{
|
||||
CMD_INITIALIZE: {
|
||||
Command: []byte{0xBE},
|
||||
Mask: []byte{0xFF},
|
||||
Response: []byte{},
|
||||
},
|
||||
CMD_TRIGGER: {
|
||||
Command: []byte{0xAC, 0x33, 0x00},
|
||||
Mask: []byte{0xFF, 0xFF, 0xFF},
|
||||
Response: []byte{0x1C, 0x5D, 0x10, 0x66, 0x01, 0xD2, 0x93},
|
||||
},
|
||||
CMD_SOFTRESET: {
|
||||
Command: []byte{0xBA},
|
||||
Mask: []byte{0xFF},
|
||||
Response: []byte{},
|
||||
},
|
||||
CMD_STATUS: {
|
||||
Command: []byte{0x71},
|
||||
Mask: []byte{0xFF},
|
||||
Response: []byte{0x1C},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package aht20
|
||||
|
||||
import "errors"
|
||||
|
||||
const (
|
||||
Address = 0x38
|
||||
|
||||
CMD_INITIALIZE = 0xBE
|
||||
CMD_STATUS = 0x71
|
||||
CMD_TRIGGER = 0xAC
|
||||
CMD_SOFTRESET = 0xBA
|
||||
|
||||
STATUS_BUSY = 0x80
|
||||
STATUS_CALIBRATED = 0x08
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBusy = errors.New("device busy")
|
||||
ErrTimeout = errors.New("timeout")
|
||||
)
|
||||
+4
-3
@@ -5,13 +5,14 @@
|
||||
package amg88xx // import "tinygo.org/x/drivers/amg88xx"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a AMG88xx device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
data []uint8
|
||||
interruptMode InterruptMode
|
||||
@@ -27,7 +28,7 @@ type Config struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: AddressHigh,
|
||||
|
||||
+27
-28
@@ -6,6 +6,8 @@ package apa102 // import "tinygo.org/x/drivers/apa102"
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -19,55 +21,52 @@ const (
|
||||
GRB
|
||||
)
|
||||
|
||||
var startFrame = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
|
||||
// Device wraps APA102 SPI LEDs.
|
||||
type Device struct {
|
||||
bus SPI
|
||||
bus drivers.SPI
|
||||
Order int
|
||||
}
|
||||
|
||||
// The SPI interface specifies the minimum functionality that a bus
|
||||
// implementation needs to provide for use by the APA102 driver. Hardware
|
||||
// SPI from the TinyGo "machine" package implements this already.
|
||||
type SPI interface {
|
||||
Tx(w, r []byte) error
|
||||
buf [4]byte
|
||||
}
|
||||
|
||||
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
|
||||
func New(b SPI) Device {
|
||||
return Device{bus: b, Order: BGR}
|
||||
func New(b drivers.SPI) *Device {
|
||||
return &Device{bus: b, Order: BGR}
|
||||
}
|
||||
|
||||
// NewSoftwareSPI returns a new APA102 driver that will use a software based
|
||||
// implementation of the SPI protocol.
|
||||
func NewSoftwareSPI(sckPin, mosiPin machine.Pin, delay uint32) Device {
|
||||
return New(&bbSPI{SCK: sckPin, MOSI: mosiPin, Delay: delay})
|
||||
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
|
||||
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
|
||||
}
|
||||
|
||||
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
|
||||
// The A value (Alpha channel) is used for brightness, set to 0xff (255) for maximum.
|
||||
func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
|
||||
func (d *Device) WriteColors(cs []color.RGBA) (n int, err error) {
|
||||
d.startFrame()
|
||||
|
||||
// write data
|
||||
for _, c := range cs {
|
||||
// brightness is scaled to 5 bit value
|
||||
d.bus.Tx([]byte{0xe0 | (c.A >> 3)}, nil)
|
||||
d.buf[0] = 0xe0 | (c.A >> 3)
|
||||
|
||||
// set the colors
|
||||
switch d.Order {
|
||||
case BRG:
|
||||
d.bus.Tx([]byte{c.B}, nil)
|
||||
d.bus.Tx([]byte{c.R}, nil)
|
||||
d.bus.Tx([]byte{c.G}, nil)
|
||||
d.buf[1] = c.B
|
||||
d.buf[2] = c.R
|
||||
d.buf[3] = c.G
|
||||
case GRB:
|
||||
d.bus.Tx([]byte{c.G}, nil)
|
||||
d.bus.Tx([]byte{c.R}, nil)
|
||||
d.bus.Tx([]byte{c.B}, nil)
|
||||
d.buf[1] = c.G
|
||||
d.buf[2] = c.R
|
||||
d.buf[3] = c.B
|
||||
case BGR:
|
||||
d.bus.Tx([]byte{c.B}, nil)
|
||||
d.bus.Tx([]byte{c.G}, nil)
|
||||
d.bus.Tx([]byte{c.R}, nil)
|
||||
d.buf[1] = c.B
|
||||
d.buf[2] = c.G
|
||||
d.buf[3] = c.R
|
||||
}
|
||||
d.bus.Tx(d.buf[:], nil)
|
||||
}
|
||||
|
||||
d.endFrame(len(cs))
|
||||
@@ -76,7 +75,7 @@ func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
|
||||
}
|
||||
|
||||
// Write the raw bytes using the APA102 protocol.
|
||||
func (d Device) Write(buf []byte) (n int, err error) {
|
||||
func (d *Device) Write(buf []byte) (n int, err error) {
|
||||
d.startFrame()
|
||||
d.bus.Tx(buf, nil)
|
||||
d.endFrame(len(buf) / 4)
|
||||
@@ -85,15 +84,15 @@ func (d Device) Write(buf []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
// startFrame sends the start bytes for a strand of LEDs.
|
||||
func (d Device) startFrame() {
|
||||
d.bus.Tx([]byte{0x00, 0x00, 0x00, 0x00}, nil)
|
||||
func (d *Device) startFrame() {
|
||||
d.bus.Tx(startFrame, nil)
|
||||
}
|
||||
|
||||
// endFrame sends the end frame marker with one extra bit per LED so
|
||||
// long strands of LEDs receive the necessary termination for updates.
|
||||
// See https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/
|
||||
func (d Device) endFrame(count int) {
|
||||
func (d *Device) endFrame(count int) {
|
||||
for i := 0; i < count/16; i++ {
|
||||
d.bus.Tx([]byte{0xff}, nil)
|
||||
d.bus.Transfer(0xff)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -9,16 +9,16 @@ import "machine"
|
||||
// this more generic and include it in the TinyGo "machine" package instead.
|
||||
type bbSPI struct {
|
||||
SCK machine.Pin
|
||||
MOSI machine.Pin
|
||||
SDO machine.Pin
|
||||
Delay uint32
|
||||
}
|
||||
|
||||
// Configure sets up the SCK and MOSI pins as outputs and sets them low
|
||||
// Configure sets up the SCK and SDO pins as outputs and sets them low
|
||||
func (s *bbSPI) Configure() {
|
||||
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.MOSI.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.SCK.Low()
|
||||
s.MOSI.Low()
|
||||
s.SDO.Low()
|
||||
if s.Delay == 0 {
|
||||
s.Delay = 1
|
||||
}
|
||||
@@ -41,19 +41,20 @@ func (s *bbSPI) delay() {
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer is used to send a single byte.
|
||||
func (s *bbSPI) Transfer(b byte) {
|
||||
// Transfer matches signature of machine.SPI.Transfer() and is used to send a
|
||||
// single byte. The received data is ignored and no error will ever be returned.
|
||||
func (s *bbSPI) Transfer(b byte) (byte, error) {
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
|
||||
// half clock cycle high to start
|
||||
s.SCK.High()
|
||||
s.delay()
|
||||
|
||||
// write the value to MOSI (MSB first)
|
||||
// write the value to SDO (MSB first)
|
||||
if b&(1<<(7-i)) == 0 {
|
||||
s.MOSI.Low()
|
||||
s.SDO.Low()
|
||||
} else {
|
||||
s.MOSI.High()
|
||||
s.SDO.High()
|
||||
}
|
||||
s.delay()
|
||||
|
||||
@@ -61,8 +62,9 @@ func (s *bbSPI) Transfer(b byte) {
|
||||
s.SCK.Low()
|
||||
s.delay()
|
||||
|
||||
// for actual SPI would try to read the MISO value here
|
||||
// for actual SPI would try to read the SDI value here
|
||||
s.delay()
|
||||
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
// Package apds9960 implements a driver for APDS-9960,
|
||||
// a digital proximity, ambient light, RGB and gesture sensor.
|
||||
//
|
||||
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
|
||||
//
|
||||
package apds9960
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a APDS-9960 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
mode uint8
|
||||
gesture gestureData
|
||||
}
|
||||
|
||||
// Configuration for APDS-9960 device.
|
||||
type Configuration struct {
|
||||
ProximityPulseLength uint8
|
||||
ProximityPulseCount uint8
|
||||
GesturePulseLength uint8
|
||||
GesturePulseCount uint8
|
||||
ProximityGain uint8
|
||||
GestureGain uint8
|
||||
ColorGain uint8
|
||||
ADCIntegrationCycles uint16
|
||||
LEDBoost uint16
|
||||
threshold uint8
|
||||
sensitivity uint8
|
||||
}
|
||||
|
||||
// for gesture-related data
|
||||
type gestureData struct {
|
||||
detected uint8
|
||||
threshold uint8
|
||||
sensitivity uint8
|
||||
gXDelta int16
|
||||
gYDelta int16
|
||||
gXPrevDelta int16
|
||||
gYPrevDelta int16
|
||||
received bool
|
||||
}
|
||||
|
||||
// for enabling various device function
|
||||
type enableConfig struct {
|
||||
GEN bool
|
||||
PIEN bool
|
||||
AIEN bool
|
||||
WEN bool
|
||||
PEN bool
|
||||
AEN bool
|
||||
PON bool
|
||||
}
|
||||
|
||||
// Connected returns whether APDS-9960 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
|
||||
return data[0] == 0xAB
|
||||
}
|
||||
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
d.DisableAll() // turn off everything
|
||||
|
||||
// "default" settings
|
||||
if cfg.ProximityPulseLength == 0 {
|
||||
cfg.ProximityPulseLength = 16
|
||||
}
|
||||
if cfg.ProximityPulseCount == 0 {
|
||||
cfg.ProximityPulseCount = 64
|
||||
}
|
||||
if cfg.GesturePulseLength == 0 {
|
||||
cfg.GesturePulseLength = 16
|
||||
}
|
||||
if cfg.GesturePulseCount == 0 {
|
||||
cfg.GesturePulseCount = 64
|
||||
}
|
||||
if cfg.ProximityGain == 0 {
|
||||
cfg.ProximityGain = 1
|
||||
}
|
||||
if cfg.GestureGain == 0 {
|
||||
cfg.GestureGain = 1
|
||||
}
|
||||
if cfg.ColorGain == 0 {
|
||||
cfg.ColorGain = 4
|
||||
}
|
||||
if cfg.ADCIntegrationCycles == 0 {
|
||||
cfg.ADCIntegrationCycles = 4
|
||||
}
|
||||
if cfg.threshold == 0 {
|
||||
d.gesture.threshold = 30
|
||||
}
|
||||
if cfg.sensitivity == 0 {
|
||||
d.gesture.sensitivity = 20
|
||||
}
|
||||
|
||||
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
|
||||
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
|
||||
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
|
||||
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
|
||||
|
||||
if cfg.LEDBoost > 0 {
|
||||
d.LEDBoost(cfg.LEDBoost)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMode returns current engine mode
|
||||
func (d *Device) GetMode() uint8 {
|
||||
return d.mode
|
||||
}
|
||||
|
||||
// DisableAll turns off the device and all functions
|
||||
func (d *Device) DisableAll() {
|
||||
d.enable(enableConfig{})
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
|
||||
d.mode = MODE_NONE
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
}
|
||||
|
||||
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
|
||||
// default: 16, 64
|
||||
func (d *Device) SetProximityPulse(length, count uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||
}
|
||||
|
||||
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
|
||||
// default: 16, 64
|
||||
func (d *Device) SetGesturePulse(length, count uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||
}
|
||||
|
||||
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
|
||||
// default: 4 (~10 ms)
|
||||
func (d *Device) SetADCIntegrationCycles(cycles uint16) {
|
||||
if cycles > 256 {
|
||||
cycles = 256
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
|
||||
}
|
||||
|
||||
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
|
||||
// default: 1, 1, 4
|
||||
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
|
||||
}
|
||||
|
||||
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
|
||||
// default: 100
|
||||
func (d *Device) LEDBoost(percent uint16) {
|
||||
var v uint8
|
||||
switch percent {
|
||||
case 100:
|
||||
v = 0
|
||||
case 150:
|
||||
v = 1
|
||||
case 200:
|
||||
v = 2
|
||||
case 300:
|
||||
v = 3
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
|
||||
}
|
||||
|
||||
// Setthreshold sets threshold (0~255) for detecting gestures
|
||||
// default: 30
|
||||
func (d *Device) Setthreshold(t uint8) {
|
||||
d.gesture.threshold = t
|
||||
}
|
||||
|
||||
// Setsensitivity sets sensivity (0~100) for detecting gestures
|
||||
// default: 20
|
||||
func (d *Device) Setsensitivity(s uint8) {
|
||||
if s > 100 {
|
||||
s = 100
|
||||
}
|
||||
d.gesture.sensitivity = 100 - s
|
||||
}
|
||||
|
||||
// EnableProximity starts the proximity engine
|
||||
func (d *Device) EnableProximity() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, PEN: true, WEN: true})
|
||||
d.mode = MODE_PROXIMITY
|
||||
}
|
||||
|
||||
// ProximityAvailable reports if proximity data is available
|
||||
func (d *Device) ProximityAvailable() bool {
|
||||
if d.mode == MODE_PROXIMITY && d.readStatus("PVALID") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadProximity reads proximity data (0~255)
|
||||
func (d *Device) ReadProximity() (proximity int32) {
|
||||
if d.mode != MODE_PROXIMITY {
|
||||
return 0
|
||||
}
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
|
||||
return 255 - int32(data[0])
|
||||
}
|
||||
|
||||
// EnableColor starts the color engine
|
||||
func (d *Device) EnableColor() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, AEN: true, WEN: true})
|
||||
d.mode = MODE_COLOR
|
||||
}
|
||||
|
||||
// ColorAvailable reports if color data is available
|
||||
func (d *Device) ColorAvailable() bool {
|
||||
if d.mode == MODE_COLOR && d.readStatus("AVALID") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadColor reads color data (red, green, blue, clear color/brightness)
|
||||
func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
|
||||
if d.mode != MODE_COLOR {
|
||||
return
|
||||
}
|
||||
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
|
||||
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
|
||||
r = int32(uint16(data[3])<<8 | uint16(data[2]))
|
||||
g = int32(uint16(data[5])<<8 | uint16(data[4]))
|
||||
b = int32(uint16(data[7])<<8 | uint16(data[6]))
|
||||
return
|
||||
}
|
||||
|
||||
// EnableGesture starts the gesture engine
|
||||
func (d *Device) EnableGesture() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, PEN: true, GEN: true, WEN: true})
|
||||
d.mode = MODE_GESTURE
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
d.gesture.gXDelta = 0
|
||||
d.gesture.gYDelta = 0
|
||||
d.gesture.gXPrevDelta = 0
|
||||
d.gesture.gYPrevDelta = 0
|
||||
d.gesture.received = false
|
||||
}
|
||||
|
||||
// GestureAvailable reports if gesture data is available
|
||||
func (d *Device) GestureAvailable() bool {
|
||||
if d.mode != MODE_GESTURE {
|
||||
return false
|
||||
}
|
||||
|
||||
data := []byte{0, 0, 0, 0}
|
||||
|
||||
// check GVALID
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
|
||||
if data[0]&0x01 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// get number of data sets available in FIFO
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
|
||||
availableDataSets := data[0]
|
||||
if availableDataSets == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// read up, down, left and right proximity data from FIFO
|
||||
var dataSets [32][4]uint8
|
||||
for i := uint8(0); i < availableDataSets; i++ {
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
|
||||
for j := uint8(0); j < 4; j++ {
|
||||
dataSets[i][j] = data[j]
|
||||
}
|
||||
}
|
||||
|
||||
// gesture detection process
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
for i := uint8(0); i < availableDataSets; i++ {
|
||||
U := dataSets[i][0]
|
||||
D := dataSets[i][1]
|
||||
L := dataSets[i][2]
|
||||
R := dataSets[i][3]
|
||||
|
||||
// if all readings fall below threshold, it's possible that
|
||||
// a movement's just been made
|
||||
if U < d.gesture.threshold && D < d.gesture.threshold && L < d.gesture.threshold && R < d.gesture.threshold {
|
||||
d.gesture.received = true
|
||||
// if there were movement in the previous step (including the last data sets)
|
||||
if d.gesture.gXPrevDelta != 0 && d.gesture.gYPrevDelta != 0 {
|
||||
totalX := d.gesture.gXPrevDelta - d.gesture.gXDelta
|
||||
totalY := d.gesture.gYPrevDelta - d.gesture.gYDelta
|
||||
// if previous and current movement are in opposite directions (pass through one led then next)
|
||||
// and the difference is big enough, the gesture is recorded
|
||||
switch {
|
||||
case totalX < -int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_LEFT
|
||||
case totalX > int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_RIGHT
|
||||
case totalY > int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_DOWN
|
||||
case totalY < -int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_UP
|
||||
}
|
||||
d.gesture.gXDelta = 0
|
||||
d.gesture.gYDelta = 0
|
||||
d.gesture.gXPrevDelta = 0
|
||||
d.gesture.gYPrevDelta = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// recording current movement
|
||||
d.gesture.gXDelta = int16(R) - int16(L)
|
||||
d.gesture.gYDelta = int16(D) - int16(U)
|
||||
if d.gesture.received {
|
||||
d.gesture.received = false
|
||||
d.gesture.gXPrevDelta = d.gesture.gXDelta
|
||||
d.gesture.gYPrevDelta = d.gesture.gYDelta
|
||||
}
|
||||
}
|
||||
|
||||
return d.gesture.detected != GESTURE_NONE
|
||||
}
|
||||
|
||||
// ReadGesture reads last gesture data
|
||||
func (d *Device) ReadGesture() (gesture int32) {
|
||||
return int32(d.gesture.detected)
|
||||
}
|
||||
|
||||
// private functions
|
||||
|
||||
func (d *Device) enable(cfg enableConfig) {
|
||||
var gen, pien, aien, wen, pen, aen, pon uint8
|
||||
|
||||
if cfg.GEN {
|
||||
gen = 1
|
||||
}
|
||||
if cfg.PIEN {
|
||||
pien = 1
|
||||
}
|
||||
if cfg.AIEN {
|
||||
aien = 1
|
||||
}
|
||||
if cfg.WEN {
|
||||
wen = 1
|
||||
}
|
||||
if cfg.PEN {
|
||||
pen = 1
|
||||
}
|
||||
if cfg.AEN {
|
||||
aen = 1
|
||||
}
|
||||
if cfg.PON {
|
||||
pon = 1
|
||||
}
|
||||
|
||||
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
|
||||
|
||||
if cfg.PON {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) readStatus(param string) bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
|
||||
|
||||
switch param {
|
||||
case "CPSAT":
|
||||
return data[0]>>7&0x01 == 1
|
||||
case "PGSAT":
|
||||
return data[0]>>6&0x01 == 1
|
||||
case "PINT":
|
||||
return data[0]>>5&0x01 == 1
|
||||
case "AINT":
|
||||
return data[0]>>4&0x01 == 1
|
||||
case "PVALID":
|
||||
return data[0]>>1&0x01 == 1
|
||||
case "AVALID":
|
||||
return data[0]&0x01 == 1
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func getPulseLength(l uint8) uint8 {
|
||||
switch l {
|
||||
case 4:
|
||||
return 0
|
||||
case 8:
|
||||
return 1
|
||||
case 16:
|
||||
return 2
|
||||
case 32:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getPulseCount(c uint8) uint8 {
|
||||
if c < 1 && c > 64 {
|
||||
return 0
|
||||
}
|
||||
return c - 1
|
||||
}
|
||||
|
||||
func getProximityGain(g uint8) uint8 {
|
||||
switch g {
|
||||
case 1:
|
||||
return 0
|
||||
case 2:
|
||||
return 1
|
||||
case 4:
|
||||
return 2
|
||||
case 8:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getALSGain(g uint8) uint8 {
|
||||
switch g {
|
||||
case 1:
|
||||
return 0
|
||||
case 4:
|
||||
return 1
|
||||
case 16:
|
||||
return 2
|
||||
case 64:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package apds9960
|
||||
|
||||
const (
|
||||
|
||||
// I2C address
|
||||
ADPS9960_ADDRESS = 0x39
|
||||
|
||||
// control/status registers
|
||||
APDS9960_RAM_REG = 0x00
|
||||
APDS9960_ENABLE_REG = 0x80
|
||||
APDS9960_ATIME_REG = 0x81
|
||||
APDS9960_WTIME_REG = 0x83
|
||||
APDS9960_AILTIL_REG = 0x84
|
||||
APDS9960_AILTH_REG = 0x85
|
||||
APDS9960_AIHTL_REG = 0x86
|
||||
APDS9960_AIHTH_REG = 0x87
|
||||
APDS9960_PILT_REG = 0x89
|
||||
APDS9960_PIHT_REG = 0x8B
|
||||
APDS9960_PERS_REG = 0x8C
|
||||
APDS9960_CONFIG1_REG = 0x8D
|
||||
APDS9960_PPULSE_REG = 0x8E
|
||||
APDS9960_CONTROL_REG = 0x8F
|
||||
APDS9960_CONFIG2_REG = 0x90
|
||||
APDS9960_ID_REG = 0x92
|
||||
APDS9960_STATUS_REG = 0x93
|
||||
APDS9960_CDATAL_REG = 0x94
|
||||
APDS9960_CDATAH_REG = 0x95
|
||||
APDS9960_RDATAL_REG = 0x96
|
||||
APDS9960_RDATAH_REG = 0x97
|
||||
APDS9960_GDATAL_REG = 0x98
|
||||
APDS9960_GDATAH_REG = 0x99
|
||||
APDS9960_BDATAL_REG = 0x9A
|
||||
APDS9960_BDATAH_REG = 0x9B
|
||||
APDS9960_PDATA_REG = 0x9C
|
||||
APDS9960_POFFSET_UR_REG = 0x9D
|
||||
APDS9960_POFFSET_DL_REG = 0x9E
|
||||
APDS9960_CONFIG3_REG = 0x9F
|
||||
APDS9960_GPENTH_REG = 0xA0
|
||||
APDS9960_GEXTH_REG = 0xA1
|
||||
APDS9960_GCONF1_REG = 0xA2
|
||||
APDS9960_GCONF2_REG = 0xA3
|
||||
APDS9960_GOFFSET_U_REG = 0xA4
|
||||
APDS9960_GOFFSET_D_REG = 0xA5
|
||||
APDS9960_GOFFSET_L_REG = 0xA7
|
||||
APDS9960_GOFFSET_R_REG = 0xA9
|
||||
APDS9960_GPULSE_REG = 0xA6
|
||||
APDS9960_GCONF3_REG = 0xAA
|
||||
APDS9960_GCONF4_REG = 0xAB
|
||||
APDS9960_GFLVL_REG = 0xAE
|
||||
APDS9960_GSTATUS_REG = 0xAF
|
||||
APDS9960_IFORCE_REG = 0xE4
|
||||
APDS9960_PICLEAR_REG = 0xE5
|
||||
APDS9960_CICLEAR_REG = 0xE6
|
||||
APDS9960_AICLEAR_REG = 0xE7
|
||||
APDS9960_GFIFO_U_REG = 0xFC
|
||||
APDS9960_GFIFO_D_REG = 0xFD
|
||||
APDS9960_GFIFO_L_REG = 0xFE
|
||||
APDS9960_GFIFO_R_REG = 0xFF
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// sensor modes
|
||||
MODE_NONE = iota
|
||||
MODE_PROXIMITY
|
||||
MODE_COLOR
|
||||
MODE_GESTURE
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// detected gestures
|
||||
GESTURE_NONE = iota
|
||||
GESTURE_UP
|
||||
GESTURE_DOWN
|
||||
GESTURE_LEFT
|
||||
GESTURE_RIGHT
|
||||
)
|
||||
+4
-3
@@ -6,13 +6,14 @@ package at24cx // import "tinygo.org/x/drivers/at24cx"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a DS3231 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
pageSize uint16
|
||||
currentRAMAddress uint16
|
||||
@@ -30,7 +31,7 @@ type Config struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
// Package axp192 provides a driver for the axp192 I2C Enhanced single Cell
|
||||
// Li-Battery and Power System Management IC.
|
||||
//
|
||||
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
|
||||
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
|
||||
//
|
||||
package axp192 // import "tinygo.org/x/drivers/axp192"
|
||||
|
||||
import (
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type Error uint8
|
||||
|
||||
const (
|
||||
ErrInvalidID Error = 0x1
|
||||
)
|
||||
|
||||
func (e Error) Error() string {
|
||||
switch e {
|
||||
case ErrInvalidID:
|
||||
return "Invalid chip ID"
|
||||
default:
|
||||
return "Unknown error"
|
||||
}
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
buf []byte
|
||||
Address uint8
|
||||
}
|
||||
|
||||
// New returns AXP192 device for the provided I2C bus using default address.
|
||||
func New(i2c drivers.I2C) *Device {
|
||||
return &Device{
|
||||
bus: i2c,
|
||||
buf: make([]byte, 2),
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure the AXP192 device.
|
||||
func (d *Device) Configure(config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadPowerSupplyStatus reads power supply status.
|
||||
func (d *Device) ReadPowerSupplyStatus() uint8 {
|
||||
return d.read8bit(RegPowerSupplyStatus)
|
||||
}
|
||||
|
||||
// SetVbusIPSOutAccessManagement sets VBUS-IPSOUT access management.
|
||||
func (d *Device) SetVbusIPSOutAccessManagement(a uint8) {
|
||||
d.write1Byte(RegVbusIPSOutAccessManagement, a)
|
||||
}
|
||||
|
||||
// GetVbusIPSOutAccessManagement gets VBUS-IPSOUT access management.
|
||||
func (d *Device) GetVbusIPSOutAccessManagement() uint8 {
|
||||
return d.read8bit(RegVbusIPSOutAccessManagement)
|
||||
}
|
||||
|
||||
// SetGPIO1Control sets GPIO1 function.
|
||||
func (d *Device) SetGPIO1Control(a uint8) {
|
||||
d.write1Byte(RegGPIO1Control, a)
|
||||
}
|
||||
|
||||
// GetGPIO1Control gets GPIO1 function.
|
||||
func (d *Device) GetGPIO1Control() uint8 {
|
||||
return d.read8bit(RegGPIO1Control)
|
||||
}
|
||||
|
||||
// SetGPIO2Control sets GPIO2 function.
|
||||
func (d *Device) SetGPIO2Control(a uint8) {
|
||||
d.write1Byte(RegGPIO2Control, a)
|
||||
}
|
||||
|
||||
// GetGPIO2Control gets GPIO2 function.
|
||||
func (d *Device) GetGPIO2Control() uint8 {
|
||||
return d.read8bit(RegGPIO2Control)
|
||||
}
|
||||
|
||||
// SetGPIO20SignalStatus sets GPIO[2:0] signal status.
|
||||
func (d *Device) SetGPIO20SignalStatus(a uint8) {
|
||||
d.write1Byte(RegGPIO20SignalStatus, a)
|
||||
}
|
||||
|
||||
// GetGPIO20SignalStatus gets GPIO[2:0] signal status.
|
||||
func (d *Device) GetGPIO20SignalStatus() uint8 {
|
||||
return d.read8bit(RegGPIO20SignalStatus)
|
||||
}
|
||||
|
||||
// SetBackupBatteryChargingControl sets backup battery charge control.
|
||||
func (d *Device) SetBackupBatteryChargingControl(a uint8) {
|
||||
d.write1Byte(RegBackupBatteryChargingControl, a)
|
||||
}
|
||||
|
||||
// GetBackupBatteryChargingControl gets backup battery charge control.
|
||||
func (d *Device) GetBackupBatteryChargingControl() uint8 {
|
||||
return d.read8bit(RegBackupBatteryChargingControl)
|
||||
}
|
||||
|
||||
// SetDCDC1VoltageSet sets DC-DC1 output voltage.
|
||||
func (d *Device) SetDCDC1VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC1VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC1VoltageSet gets DC-DC1 output voltage.
|
||||
func (d *Device) GetDCDC1VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC1VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC2VoltageSet sets DC-DC2 dynamic voltage parameter.
|
||||
func (d *Device) SetDCDC2VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC2VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC2VoltageSet gets DC-DC2 dynamic voltage parameter.
|
||||
func (d *Device) GetDCDC2VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC2VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC3VoltageSet sets DC-DC3 output voltage.
|
||||
func (d *Device) SetDCDC3VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC3VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC3VoltageSet gets DC-DC3 output voltage.
|
||||
func (d *Device) GetDCDC3VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC3VoltageSet)
|
||||
}
|
||||
|
||||
// SetLDO23VoltageSet sets LDO2/3 output voltage.
|
||||
func (d *Device) SetLDO23VoltageSet(a uint8) {
|
||||
d.write1Byte(RegLDO23VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetLDO23VoltageSet gets LDO2/3 output voltage.
|
||||
func (d *Device) GetLDO23VoltageSet() uint8 {
|
||||
return d.read8bit(RegLDO23VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC13LDO23Switch sets DC-DC1/3 & LOD2/3 output control.
|
||||
func (d *Device) SetDCDC13LDO23Switch(a uint8) {
|
||||
d.write1Byte(RegDCDC13LDO23Switch, a)
|
||||
}
|
||||
|
||||
// GetDCDC13LDO23Switch gets DC-DC1/3 & LOD2/3 output control.
|
||||
func (d *Device) GetDCDC13LDO23Switch() uint8 {
|
||||
return d.read8bit(RegDCDC13LDO23Switch)
|
||||
}
|
||||
|
||||
// SetGPIO43FunctionControl sets GPIO[4:3] pin function.
|
||||
func (d *Device) SetGPIO43FunctionControl(a uint8) {
|
||||
d.write1Byte(RegGPIO43FunctionControl, a)
|
||||
}
|
||||
|
||||
// GetGPIO43FunctionControl gets GPIO[4:3] pin function.
|
||||
func (d *Device) GetGPIO43FunctionControl() uint8 {
|
||||
return d.read8bit(RegGPIO43FunctionControl)
|
||||
}
|
||||
|
||||
// SetPEKParameterSet sets PEK press key parameter.
|
||||
func (d *Device) SetPEKParameterSet(a uint8) {
|
||||
d.write1Byte(RegPEKParameterSet, a)
|
||||
}
|
||||
|
||||
// GetPEKParameterSet gets PEK press key parameter.
|
||||
func (d *Device) GetPEKParameterSet() uint8 {
|
||||
return d.read8bit(RegPEKParameterSet)
|
||||
}
|
||||
|
||||
// SetADCEnableSet sets ADC enable 1.
|
||||
func (d *Device) SetADCEnableSet(a uint8) {
|
||||
d.write1Byte(RegADCEnableSet, a)
|
||||
}
|
||||
|
||||
// GetADCEnableSet gets ADC enable 1.
|
||||
func (d *Device) GetADCEnableSet() uint8 {
|
||||
return d.read8bit(RegADCEnableSet)
|
||||
}
|
||||
|
||||
// SetGPIO43SignalStatus sets GPIO[4:3] signal status.
|
||||
func (d *Device) SetGPIO43SignalStatus(a uint8) {
|
||||
d.write1Byte(RegGPIO43SignalStatus, a)
|
||||
}
|
||||
|
||||
// GetGPIO43SignalStatus gets GPIO[4:3] signal status.
|
||||
func (d *Device) GetGPIO43SignalStatus() uint8 {
|
||||
return d.read8bit(RegGPIO43SignalStatus)
|
||||
}
|
||||
|
||||
// SetDCVoltage sets DC voltage.
|
||||
func (d *Device) SetDCVoltage(number uint8, voltage uint16) {
|
||||
if voltage < 700 {
|
||||
voltage = 0
|
||||
} else {
|
||||
voltage = (voltage - 700) / 25
|
||||
}
|
||||
|
||||
switch number {
|
||||
case 0:
|
||||
v := d.GetDCDC1VoltageSet()
|
||||
d.SetDCDC1VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
case 1:
|
||||
v := d.GetDCDC2VoltageSet()
|
||||
d.SetDCDC2VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
case 2:
|
||||
v := d.GetDCDC3VoltageSet()
|
||||
d.SetDCDC3VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
}
|
||||
}
|
||||
|
||||
// SetLDOVoltage sets LDO voltage.
|
||||
func (d *Device) SetLDOVoltage(number uint8, voltage uint16) {
|
||||
if voltage > 3300 {
|
||||
voltage = 15
|
||||
} else {
|
||||
voltage = (voltage / 100) - 18
|
||||
}
|
||||
|
||||
switch number {
|
||||
case 2:
|
||||
v := d.GetLDO23VoltageSet()
|
||||
d.SetLDO23VoltageSet((v & 0x0F) | (uint8(voltage) << 4))
|
||||
break
|
||||
case 3:
|
||||
v := d.GetLDO23VoltageSet()
|
||||
d.SetLDO23VoltageSet((v & 0xF0) | uint8(voltage))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// SetLDOEnable enable LDO.
|
||||
func (d *Device) SetLDOEnable(number uint8, state bool) {
|
||||
mark := uint8(0x01)
|
||||
mark <<= number
|
||||
switch number {
|
||||
case 2:
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
d.SetDCDC13LDO23Switch(v | mark)
|
||||
case 3:
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
d.SetDCDC13LDO23Switch(v & (^mark))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) write1Byte(reg, data uint8) {
|
||||
d.bus.WriteRegister(d.Address, reg, []byte{data})
|
||||
}
|
||||
|
||||
func (d *Device) read8bit(reg uint8) uint8 {
|
||||
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
|
||||
return d.buf[0]
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package axp192
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
axp192orig "tinygo.org/x/drivers/axp192"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a AXP192 device.
|
||||
type Device struct {
|
||||
*axp192orig.Device
|
||||
LED Pin
|
||||
RST Pin
|
||||
SPK_EN Pin
|
||||
}
|
||||
|
||||
// New creates a new AXP192 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(i2c drivers.I2C) *Device {
|
||||
d := axp192orig.New(i2c)
|
||||
|
||||
axp := &Device{
|
||||
Device: d,
|
||||
}
|
||||
axp.LED = Pin{pin: 1, axp: axp}
|
||||
axp.SPK_EN = Pin{pin: 2, axp: axp}
|
||||
axp.RST = Pin{pin: 4, axp: axp}
|
||||
|
||||
axp.begin()
|
||||
|
||||
return axp
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication
|
||||
func (d *Device) Configure(config Config) error {
|
||||
return d.Device.Configure(axp192orig.Config{})
|
||||
}
|
||||
|
||||
func (d *Device) begin() {
|
||||
d.SetVbusIPSOutAccessManagement((d.GetVbusIPSOutAccessManagement() & 0x04) | 0x02)
|
||||
d.SetGPIO1Control(d.GetGPIO1Control() & 0xF8)
|
||||
d.SetGPIO2Control(d.GetGPIO2Control() & 0xF8)
|
||||
d.SetBackupBatteryChargingControl((d.GetBackupBatteryChargingControl() & 0x1C) | 0xA2)
|
||||
d.SetESPVoltage(3350)
|
||||
d.SetLcdVoltage(3300)
|
||||
d.SetLDOVoltage(2, 3300) //Periph power voltage preset (LCD_logic, SD card)
|
||||
d.SetLDOVoltage(3, 2000) //Vibrator power voltage preset
|
||||
|
||||
d.SetLDOEnable(2, true)
|
||||
d.SetDCDC3(true) // LCD Backlight
|
||||
// GPIO4 : LCD Reset
|
||||
d.SetGPIO43FunctionControl((d.GetGPIO43FunctionControl() & 0x72) | 0x84)
|
||||
// Power On/Off Setting
|
||||
d.SetPEKParameterSet(0x4C)
|
||||
d.SetADCEnableSet(0xFF)
|
||||
|
||||
d.RST.Low()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
d.RST.High()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
// ToggleLED toggles LED connected to AXP192.
|
||||
func (d *Device) ToggleLED() {
|
||||
v := d.GetGPIO20SignalStatus()
|
||||
if (v & 0x02) > 0 {
|
||||
d.SetGPIO20SignalStatus(v & 0xFD)
|
||||
} else {
|
||||
d.SetGPIO20SignalStatus(v | 0x02)
|
||||
}
|
||||
}
|
||||
|
||||
// SetESPVoltage sets voltage of ESP32.
|
||||
func (d *Device) SetESPVoltage(voltage uint16) {
|
||||
if voltage >= 3000 && voltage <= 3400 {
|
||||
d.SetDCVoltage(0, voltage)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLcdVoltage sets voltage of LCD.
|
||||
func (d *Device) SetLcdVoltage(voltage uint16) {
|
||||
if voltage >= 2500 && voltage <= 3300 {
|
||||
d.SetDCVoltage(2, voltage)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDCDC3 enables or disables DCDC3.
|
||||
func (d *Device) SetDCDC3(State bool) {
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
if State == true {
|
||||
v = (1 << 1) | v
|
||||
} else {
|
||||
v = ^(uint8(1) << 1) & v
|
||||
}
|
||||
d.SetDCDC13LDO23Switch(v)
|
||||
}
|
||||
|
||||
// Pin is a single pin on AXP192.
|
||||
type Pin struct {
|
||||
pin uint8
|
||||
axp *Device
|
||||
}
|
||||
|
||||
// High sets this GPIO pin to high.
|
||||
func (p Pin) High() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
p.axp.SetGPIO20SignalStatus(v | 0x02)
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
v |= uint8(0x02)
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Low sets this GPIO pin to low.
|
||||
func (p Pin) Low() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
p.axp.SetGPIO20SignalStatus(v & 0xFD)
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
v &= ^uint8(0x02)
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle switches an output pin from low to high or from high to low.
|
||||
func (p Pin) Toggle() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
if (v & 0x02) == 0 {
|
||||
p.axp.SetGPIO20SignalStatus(v | 0x02)
|
||||
} else {
|
||||
p.axp.SetGPIO20SignalStatus(v & 0xFD)
|
||||
}
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
if (v & 0x02) == 0 {
|
||||
v |= uint8(0x02)
|
||||
} else {
|
||||
v &= ^uint8(0x02)
|
||||
}
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package axp192
|
||||
|
||||
// power supply control class
|
||||
// 0x00 Power supply status register
|
||||
// 0x01 Power supply mode/charging status register
|
||||
// 0x04 OTG VBUS status register
|
||||
// 0x06‐09 Data buffer register
|
||||
// 0x10 EXTEN & DC‐DC2 switch register
|
||||
// 0x12 DC‐DC1/3 & LDO2/3switch register
|
||||
// 0x23 DC‐DC2 voltage set register
|
||||
// 0x25 DC‐DC2 voltage slope set register
|
||||
// 0x26 DC‐DC1voltage set register
|
||||
// 0x27 DC‐DC3 voltage set register
|
||||
// 0x28 LDO2/3 voltage set register
|
||||
// 0x30 VBUS‐IPSOUT access set register
|
||||
// 0x31 VOFF power off voltage set register
|
||||
// 0x32 Power off、battery detect、CHGLED control register
|
||||
// 0x33 Charging control register1
|
||||
// 0x34 Charging control register2
|
||||
// 0x35 Backup battery charging control register
|
||||
// 0x36 PEK parameter set register
|
||||
// 0x37 DCDC switch frequency set register
|
||||
// 0x38 Battery charging under temperature warning set register
|
||||
// 0x39 Battery charging over temperature warning set register
|
||||
// 0x3A APS under voltage Level1 set register
|
||||
// 0x3B APS under voltage Level2 set register
|
||||
// 0x3C Battery discharging under temperature warning set register
|
||||
// 0x3D Battery discharging over temperature warning set register
|
||||
// 0x80 DCDC mode set register
|
||||
// 0x82 ADC enable set register 1
|
||||
// 0x83 ADC enable set register 2
|
||||
// 0x84 ADC sample frequency set, TS pin control register
|
||||
// 0x85 GPIO [3:0] input range set register
|
||||
// 0x8A Timer control register
|
||||
// 0x8B VBUS monitor set register
|
||||
// 0x8F Over temperature power off control register
|
||||
|
||||
// GPIO control class
|
||||
// 0x90 GPIO0 control register
|
||||
// 0x91 GPIO0 LDO mode output voltage set register
|
||||
// 0x92 GPIO1 control register
|
||||
// 0x93 GPIO2 control register
|
||||
// 0x94 GPIO[2:0] signal status register
|
||||
// 0x95 GPIO[4:3] function control register
|
||||
// 0x96 GPIO[4:3] signal status register
|
||||
// 0x97 GPIO[2:0] pull down control register
|
||||
// 0x98 PWM1 frequency set register
|
||||
// 0x99 PWM1 duty ratio set register 1
|
||||
// 0x9A PWM1 duty ratio set register 2
|
||||
// 0x9B PWM2 frequency set register
|
||||
// 0x9C PWM2 duty ratio set register 1
|
||||
// 0x9D PWM2 duty ratio set register 2
|
||||
// 0x9E GPIO5 control register
|
||||
|
||||
// IRQ control class
|
||||
// 0x40 IRQ enable control register 1
|
||||
// 0x41 IRQ enable control register 2
|
||||
// 0x42 IRQ enable control register 3
|
||||
// 0x43 IRQ enable control register 4
|
||||
// 0x44 IRQ status register 1
|
||||
// 0x45 IRQ status register 2
|
||||
// 0x46 IRQ status register 3
|
||||
// 0x47 IRQ status register 4
|
||||
|
||||
// ADC data class
|
||||
// 0x56 ACIN voltage ADC data high 8 bit
|
||||
// 0x57 ACIN voltage ADC data low 4 bit
|
||||
// 0x58 ACIN current ADC data high 8 bit
|
||||
// 0x59 ACIN current ADC data low 4 bit
|
||||
// 0x5A VBUS voltage ADC data high 8 bit
|
||||
// 0x5B VBUS voltage ADC data low 4 bit
|
||||
// 0x5C VBUS current ADC data high 8 bit
|
||||
// 0x5D VBUS current ADC data low 4 bit
|
||||
// 0x5E AXP192 internal temperature monitor ADC data High 8 bit
|
||||
// 0x5F AXP192 internal temperature monitor ADC data low 4 bit
|
||||
// 0x62 TS input ADC data High 8 bit,monitor battery temperature by default
|
||||
// 0x63 TS input ADC data low 4 bit,monitor battery temperature by default
|
||||
// 0x64 GPIO0 voltage ADC data high 8 bit
|
||||
// 0x65 GPIO0 voltage ADC data low 4 bit
|
||||
// 0x66 GPIO1 voltage ADC data high 8 bit
|
||||
// 0x67 GPIO1 voltage ADC data low 4 bit
|
||||
// 0x68 GPIO2 voltage ADC data high 8 bit
|
||||
// 0x69 GPIO2 voltage ADC data low 4 bit
|
||||
// 0x6A GPIO[3] voltage ADC data high 8 bit
|
||||
// 0x6B GPIO[3] voltage ADC data low 4 bit
|
||||
// 0x70 Battery instantaneous power high 8 bit
|
||||
// 0x71 Battery instantaneous power middle 8 bit
|
||||
// 0x72 Battery instantaneous power low 8 bit
|
||||
// 0x78 Battery voltage high 8 bit
|
||||
// 0x79 Battery voltage low 4 bit
|
||||
// 0x7A Battery charging current high 8 bit
|
||||
// 0x7B Battery charging current low 5 bit
|
||||
// 0x7C Battery discharging current high 8 bit
|
||||
// 0x7D Battery discharging current low 5 bit
|
||||
// 0x7E APS voltage high 8 bit
|
||||
// 0x7F APS voltage low 4 bit
|
||||
// 0xB0 Battery charging coulomb counter data register 3
|
||||
// 0xB1 Battery charging coulomb counter data register 2
|
||||
// 0xB2 Battery charging coulomb counter data register 1
|
||||
// 0xB3 Battery charging coulomb counter data register 0
|
||||
// 0xB4 Battery discharging coulomb counter data register 3
|
||||
// 0xB5 Battery discharging coulomb counter data register 2
|
||||
// 0xB6 Battery discharging coulomb counter data register 1
|
||||
// 0xB7 Battery discharging coulomb counter data register 0
|
||||
// 0xB8 Coulomb counter control register
|
||||
|
||||
const (
|
||||
// Address is default I2C address.
|
||||
Address = 0x34
|
||||
|
||||
RegPowerSupplyStatus = 0x00
|
||||
RegDCDC13LDO23Switch = 0x12
|
||||
RegVbusIPSOutAccessManagement = 0x30
|
||||
RegBackupBatteryChargingControl = 0x35
|
||||
RegDCDC2VoltageSet = 0x25
|
||||
RegDCDC1VoltageSet = 0x26
|
||||
RegDCDC3VoltageSet = 0x27
|
||||
RegLDO23VoltageSet = 0x28
|
||||
RegPEKParameterSet = 0x36
|
||||
RegADCEnableSet = 0x82
|
||||
|
||||
RegGPIO1Control = 0x92
|
||||
RegGPIO2Control = 0x93
|
||||
RegGPIO20SignalStatus = 0x94
|
||||
RegGPIO43FunctionControl = 0x95
|
||||
RegGPIO43SignalStatus = 0x96
|
||||
)
|
||||
+3
-3
@@ -8,7 +8,7 @@ package bh1750 // import "tinygo.org/x/drivers/bh1750"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// SamplingMode is the sampling's resolution of the measurement
|
||||
@@ -16,7 +16,7 @@ type SamplingMode byte
|
||||
|
||||
// Device wraps an I2C connection to a bh1750 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
mode SamplingMode
|
||||
}
|
||||
@@ -25,7 +25,7 @@ type Device struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
|
||||
+4
-5
@@ -1,15 +1,14 @@
|
||||
// Package blinkm implements a driver for the BlinkM I2C RGB LED.
|
||||
//
|
||||
// Datasheet: http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf
|
||||
//
|
||||
package blinkm // import "tinygo.org/x/drivers/blinkm"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
)
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// Device wraps an I2C connection to a BlinkM device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
}
|
||||
|
||||
@@ -17,7 +16,7 @@ type Device struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus, Address}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -7,8 +7,9 @@
|
||||
package bme280
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"math"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// calibrationCoefficients reads at startup and stores the calibration coefficients
|
||||
@@ -35,7 +36,7 @@ type calibrationCoefficients struct {
|
||||
|
||||
// Device wraps an I2C connection to a BME280 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
calibrationCoefficients calibrationCoefficients
|
||||
}
|
||||
@@ -44,7 +45,7 @@ type Device struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package bmi160
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// DeviceSPI is the SPI interface to a BMI160 accelerometer/gyroscope. There is
|
||||
// also an I2C interface, but it is not yet supported.
|
||||
type DeviceSPI struct {
|
||||
// Chip select pin
|
||||
CSB machine.Pin
|
||||
|
||||
buf [7]byte
|
||||
|
||||
// SPI bus (requires chip select to be usable).
|
||||
Bus drivers.SPI
|
||||
}
|
||||
|
||||
// NewSPI returns a new device driver. The pin and SPI interface are not
|
||||
// touched, provide a fully configured SPI object and call Configure to start
|
||||
// using this device.
|
||||
func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
|
||||
return &DeviceSPI{
|
||||
CSB: csb, // chip select
|
||||
Bus: spi,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure configures the BMI160 for use. It configures the CSB pin and
|
||||
// configures the BMI160, but it does not configure the SPI interface (it is
|
||||
// assumed to be up and running).
|
||||
func (d *DeviceSPI) Configure() error {
|
||||
d.CSB.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
d.CSB.High()
|
||||
|
||||
// The datasheet recommends doing a register read from address 0x7F to get
|
||||
// SPI communication going:
|
||||
// > If CSB sees a rising edge after power-up, the BMI160 interface switches
|
||||
// > to SPI until a reset or the next power-up occurs. Therefore, a CSB
|
||||
// > rising edge is needed before starting the SPI communication. Hence, it
|
||||
// > is recommended to perform a SPI single read access to the ADDRESS 0x7F
|
||||
// > before the actual communication in order to use the SPI interface.
|
||||
d.readRegister(0x7F)
|
||||
|
||||
// Power up the accelerometer. 0b0001_00nn is the command format, with 0b01
|
||||
// indicating normal mode.
|
||||
d.runCommand(0b0001_0001)
|
||||
|
||||
// Power up the gyroscope. 0b0001_01nn is the command format, with 0b01
|
||||
// indicating normal mode.
|
||||
d.runCommand(0b0001_0101)
|
||||
|
||||
// Wait until the device is fully initialized. Even after the command has
|
||||
// finished, the gyroscope may not be fully powered on. Therefore, wait
|
||||
// until we get an expected value.
|
||||
// This takes 30ms or so.
|
||||
for {
|
||||
// Wait for the acc_pmu_status and gyr_pmu_status to both be 0b01.
|
||||
if d.readRegister(reg_PMU_STATUS) == 0b0001_0100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connected check whether the device appears to be properly connected. It reads
|
||||
// the CHIPID, which must be 0xD1 for the BMI160.
|
||||
func (d *DeviceSPI) Connected() bool {
|
||||
return d.readRegister(reg_CHIPID) == 0xD1
|
||||
}
|
||||
|
||||
// Reset restores the device to the state after power up. This can be useful to
|
||||
// easily disable the accelerometer and gyroscope to reduce current consumption.
|
||||
func (d *DeviceSPI) Reset() error {
|
||||
d.runCommand(0xB6) // softreset
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
|
||||
data := d.buf[:3]
|
||||
data[0] = 0x80 | reg_TEMPERATURE_0
|
||||
data[1] = 0
|
||||
data[2] = 0
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawTemperature := int16(uint16(data[1]) | uint16(data[2])<<8)
|
||||
// 0x0000 is 23°C
|
||||
// 0x7fff is ~87°C
|
||||
// We use 0x8000 instead of 0x7fff to make the formula easier. The result
|
||||
// should be near identical and shouldn't affect the result too much (the
|
||||
// temperature sensor has an offset of around 2°C so isn't very reliable).
|
||||
// So the formula is as follows:
|
||||
// 1. Scale from 0x0000..0x8000 to 0..(87-23).
|
||||
// rawTemperature * (87-23) / 0x8000
|
||||
// 2. Convert to centidegrees.
|
||||
// rawTemperature * 1000 * (87-23) / 0x8000
|
||||
// 3. Add 23°C offset.
|
||||
// rawTemperature * 1000 * (87-23) / 0x8000 + 23000
|
||||
// 4. Simplify.
|
||||
// rawTemperature * 1000 * 64 / 0x8000 + 23000
|
||||
// rawTemperature * 64000 / 0x8000 + 23000
|
||||
// rawTemperature * 125 / 64 + 23000
|
||||
temperature = int32(rawTemperature)*125/64 + 23000
|
||||
return
|
||||
}
|
||||
|
||||
// ReadAcceleration reads the current acceleration from the device and returns
|
||||
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
|
||||
// and the sensor is not moving the returned value will be around 1000000 or
|
||||
// -1000000.
|
||||
func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
|
||||
data := d.buf[:7]
|
||||
data[0] = 0x80 | reg_ACC_XL
|
||||
for i := 1; i < len(data); i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Now do two things:
|
||||
// 1. merge the two values to a 16-bit number (and cast to a 32-bit integer)
|
||||
// 2. scale the value to bring it in the -1000000..1000000 range.
|
||||
// This is done with a trick. What we do here is essentially multiply by
|
||||
// 1000000 and divide by 16384 to get the original scale, but to avoid
|
||||
// overflow we do it at 1/64 of the value:
|
||||
// 1000000 / 64 = 15625
|
||||
// 16384 / 64 = 256
|
||||
x = int32(int16(uint16(data[1])|uint16(data[2])<<8)) * 15625 / 256
|
||||
y = int32(int16(uint16(data[3])|uint16(data[4])<<8)) * 15625 / 256
|
||||
z = int32(int16(uint16(data[5])|uint16(data[6])<<8)) * 15625 / 256
|
||||
return
|
||||
}
|
||||
|
||||
// ReadRotation reads the current rotation from the device and returns it in
|
||||
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
|
||||
// rotation along one axis and while doing so integrate all values over time,
|
||||
// you would get a value close to 360000000.
|
||||
func (d *DeviceSPI) ReadRotation() (x int32, y int32, z int32, err error) {
|
||||
data := d.buf[:7]
|
||||
data[0] = 0x80 | reg_GYR_XL
|
||||
for i := 1; i < len(data); i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// First the value is converted from a pair of bytes to a signed 16-bit
|
||||
// value and then to a signed 32-bit value to avoid integer overflow.
|
||||
// Then the value is scaled to µ°/s (micro-degrees per second).
|
||||
// The default is 2000°/s full scale range for -32768..32767.
|
||||
// The formula works as follows (taking X as an example):
|
||||
// 1. Scale from 32768 to 2000. This means that it is in °/s units.
|
||||
// rawX * 2000 / 32768
|
||||
// 2. Scale to µ°/s by multiplying by 1e6.
|
||||
// rawX * 1e6 * 2000 / 32768
|
||||
// 3. Simplify.
|
||||
// rawX * 2e9 / 32768
|
||||
// rawX * 1953125 / 32
|
||||
rawX := int32(int16(uint16(data[1]) | uint16(data[2])<<8))
|
||||
rawY := int32(int16(uint16(data[3]) | uint16(data[4])<<8))
|
||||
rawZ := int32(int16(uint16(data[5]) | uint16(data[6])<<8))
|
||||
x = int32(int64(rawX) * 1953125 / 32)
|
||||
y = int32(int64(rawY) * 1953125 / 32)
|
||||
z = int32(int64(rawZ) * 1953125 / 32)
|
||||
return
|
||||
}
|
||||
|
||||
// runCommand runs a BMI160 command through the CMD register. It waits for the
|
||||
// command to complete before returning.
|
||||
func (d *DeviceSPI) runCommand(command uint8) {
|
||||
d.writeRegister(reg_CMD, command)
|
||||
for {
|
||||
response := d.readRegister(reg_CMD)
|
||||
if response == 0 {
|
||||
return // command was completed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readRegister reads from a single BMI160 register. It should only be used for
|
||||
// single register reads, not for reading multiple registers at once.
|
||||
func (d *DeviceSPI) readRegister(address uint8) uint8 {
|
||||
// I don't know why but it appears necessary to sleep for a bit here.
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
data := d.buf[:2]
|
||||
data[0] = 0x80 | address
|
||||
data[1] = 0
|
||||
d.CSB.Low()
|
||||
d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
return data[1]
|
||||
}
|
||||
|
||||
// writeRegister writes a single byte BMI160 register. It should only be used
|
||||
// for writing to a single register.
|
||||
func (d *DeviceSPI) writeRegister(address, data uint8) {
|
||||
// I don't know why but it appears necessary to sleep for a bit here.
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
buf := d.buf[:2]
|
||||
buf[0] = address
|
||||
buf[1] = data
|
||||
|
||||
d.CSB.Low()
|
||||
d.Bus.Tx(buf, buf)
|
||||
d.CSB.High()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package bmi160
|
||||
|
||||
const (
|
||||
reg_CHIPID = 0x00
|
||||
reg_ERR_REG = 0x02
|
||||
reg_PMU_STATUS = 0x03
|
||||
reg_MAG_XL = 0x04
|
||||
reg_MAG_XH = 0x05
|
||||
reg_MAG_YL = 0x06
|
||||
reg_MAG_YH = 0x07
|
||||
reg_MAG_ZL = 0x08
|
||||
reg_MAG_ZH = 0x09
|
||||
reg_RHALL_L = 0x0A
|
||||
reg_RHALL_H = 0x0B
|
||||
reg_GYR_XL = 0x0C
|
||||
reg_GYR_XH = 0x0D
|
||||
reg_GYR_YL = 0x0E
|
||||
reg_GYR_YH = 0x0F
|
||||
reg_GYR_ZL = 0x10
|
||||
reg_GYR_ZH = 0x11
|
||||
reg_ACC_XL = 0x12
|
||||
reg_ACC_XH = 0x13
|
||||
reg_ACC_YL = 0x14
|
||||
reg_ACC_YH = 0x15
|
||||
reg_ACC_ZL = 0x16
|
||||
reg_ACC_ZH = 0x17
|
||||
reg_SENSORTIME_0 = 0x18
|
||||
reg_SENSORTIME_1 = 0x19
|
||||
reg_SENSORTIME_2 = 0x1A
|
||||
reg_STATUS = 0x1B
|
||||
reg_INT_STATUS_0 = 0x1C
|
||||
reg_INT_STATUS_1 = 0x1D
|
||||
reg_INT_STATUS_2 = 0x1E
|
||||
reg_INT_STATUS_3 = 0x1F
|
||||
reg_TEMPERATURE_0 = 0x20
|
||||
reg_TEMPERATURE_1 = 0x21
|
||||
reg_FIFO_LENGTH_0 = 0x22
|
||||
reg_FIFO_LENGTH_1 = 0x23
|
||||
reg_FIFO_DATA = 0x24
|
||||
|
||||
// ...
|
||||
|
||||
reg_CMD = 0x7E
|
||||
)
|
||||
+7
-7
@@ -9,7 +9,7 @@ package bmp180 // import "tinygo.org/x/drivers/bmp180"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// OversamplingMode is the oversampling ratio of the pressure measurement.
|
||||
@@ -32,7 +32,7 @@ type calibrationCoefficients struct {
|
||||
|
||||
// Device wraps an I2C connection to a BMP180 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
mode OversamplingMode
|
||||
calibrationCoefficients calibrationCoefficients
|
||||
@@ -43,7 +43,7 @@ type Device struct {
|
||||
//
|
||||
// This function only creates the Device object, it does not initialize the device.
|
||||
// You must call Configure() first in order to use the device itself.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
@@ -125,7 +125,7 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
}
|
||||
|
||||
// rawTemp returns the sensor's raw values of the temperature
|
||||
func (d *Device) rawTemp() (int16, error) {
|
||||
func (d *Device) rawTemp() (int32, error) {
|
||||
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_TEMP})
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
data := make([]byte, 2)
|
||||
@@ -133,12 +133,12 @@ func (d *Device) rawTemp() (int16, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return readInt(data[0], data[1]), nil
|
||||
return int32(uint16(data[0])<<8 | uint16(data[1])), nil
|
||||
}
|
||||
|
||||
// calculateB5 calculates intermediate value B5 as per page 15 of datasheet
|
||||
func (d *Device) calculateB5(rawTemp int16) int32 {
|
||||
x1 := (int32(rawTemp) - int32(d.calibrationCoefficients.ac6)) * int32(d.calibrationCoefficients.ac5) >> 15
|
||||
func (d *Device) calculateB5(rawTemp int32) int32 {
|
||||
x1 := (rawTemp - int32(d.calibrationCoefficients.ac6)) * int32(d.calibrationCoefficients.ac5) >> 15
|
||||
x2 := int32(d.calibrationCoefficients.mc) << 11 / (x1 + int32(d.calibrationCoefficients.md))
|
||||
return x1 + x2
|
||||
}
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
package bmp280
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// OversamplingMode is the oversampling ratio of the temperature or pressure measurement.
|
||||
type Oversampling uint
|
||||
|
||||
// Mode is the Power Mode.
|
||||
type Mode uint
|
||||
|
||||
// Standby is the inactive period between the reads when the sensor is in normal power mode.
|
||||
type Standby uint
|
||||
|
||||
// Filter unwanted changes in measurement caused by external (environmental) or internal changes (IC).
|
||||
type Filter uint
|
||||
|
||||
// Device wraps an I2C connection to a BMP280 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
cali calibrationCoefficients
|
||||
Temperature Oversampling
|
||||
Pressure Oversampling
|
||||
Mode Mode
|
||||
Standby Standby
|
||||
Filter Filter
|
||||
}
|
||||
|
||||
type calibrationCoefficients struct {
|
||||
// Temperature compensation
|
||||
t1 uint16
|
||||
t2 int16
|
||||
t3 int16
|
||||
|
||||
// Pressure compensation
|
||||
p1 uint16
|
||||
p2 int16
|
||||
p3 int16
|
||||
p4 int16
|
||||
p5 int16
|
||||
p6 int16
|
||||
p7 int16
|
||||
p8 int16
|
||||
p9 int16
|
||||
}
|
||||
|
||||
// New creates a new BMP280 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not initialize the device.
|
||||
// You must call Configure() first in order to use the device itself.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
// Connected returns whether a BMP280 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := make([]byte, 1)
|
||||
d.bus.ReadRegister(uint8(d.Address), REG_ID, data)
|
||||
return data[0] == CHIP_ID
|
||||
}
|
||||
|
||||
// Reset preforms complete power-on-reset procedure.
|
||||
// It is required to call Configure afterwards.
|
||||
func (d *Device) Reset() {
|
||||
d.bus.WriteRegister(uint8(d.Address), REG_RESET, []byte{CMD_RESET})
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication and
|
||||
// read the calibration coefficients.
|
||||
func (d *Device) Configure(standby Standby, filter Filter, temp Oversampling, pres Oversampling, mode Mode) {
|
||||
d.Standby = standby
|
||||
d.Filter = filter
|
||||
d.Temperature = temp
|
||||
d.Pressure = pres
|
||||
d.Mode = mode
|
||||
|
||||
// Write the configuration (standby, filter, spi 3 wire)
|
||||
config := uint(d.Standby<<5) | uint(d.Filter<<2) | 0x00
|
||||
d.bus.WriteRegister(uint8(d.Address), REG_CONFIG, []byte{byte(config)})
|
||||
|
||||
// Write the control (temperature oversampling, pressure oversampling,
|
||||
config = uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(d.Mode)
|
||||
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
||||
|
||||
// Read Calibration data
|
||||
data := make([]byte, 24)
|
||||
err := d.bus.ReadRegister(uint8(d.Address), REG_CALI, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Datasheet: 3.11.2 Trimming parameter readout
|
||||
d.cali.t1 = readUintLE(data[0], data[1])
|
||||
d.cali.t2 = readIntLE(data[2], data[3])
|
||||
d.cali.t3 = readIntLE(data[4], data[5])
|
||||
|
||||
d.cali.p1 = readUintLE(data[6], data[7])
|
||||
d.cali.p2 = readIntLE(data[8], data[9])
|
||||
d.cali.p3 = readIntLE(data[10], data[11])
|
||||
d.cali.p4 = readIntLE(data[12], data[13])
|
||||
d.cali.p5 = readIntLE(data[14], data[15])
|
||||
d.cali.p6 = readIntLE(data[16], data[17])
|
||||
d.cali.p7 = readIntLE(data[18], data[19])
|
||||
d.cali.p8 = readIntLE(data[20], data[21])
|
||||
d.cali.p9 = readIntLE(data[22], data[23])
|
||||
}
|
||||
|
||||
// PrintCali prints the Calibration information.
|
||||
func (d *Device) PrintCali() {
|
||||
println("T1:", d.cali.t1)
|
||||
println("T2:", d.cali.t2)
|
||||
println("T3:", d.cali.t3)
|
||||
|
||||
println("P1:", d.cali.p1)
|
||||
println("P2:", d.cali.p2)
|
||||
println("P3:", d.cali.p3)
|
||||
println("P4:", d.cali.p4)
|
||||
println("P5:", d.cali.p5)
|
||||
println("P6:", d.cali.p6)
|
||||
println("P7:", d.cali.p7)
|
||||
println("P8:", d.cali.p8)
|
||||
println("P9:", d.cali.p9, "\n")
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
data, err := d.readData(REG_TEMP, 3)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rawTemp := convert3Bytes(data[0], data[1], data[2])
|
||||
|
||||
// Datasheet: 8.2 Compensation formula in 32 bit fixed point
|
||||
// Temperature compensation
|
||||
var1 := ((rawTemp >> 3) - int32(d.cali.t1<<1)) * int32(d.cali.t2) >> 11
|
||||
var2 := (((rawTemp >> 4) - int32(d.cali.t1)) * ((rawTemp >> 4) - int32(d.cali.t1)) >> 12) *
|
||||
int32(d.cali.t3) >> 14
|
||||
|
||||
tFine := var1 + var2
|
||||
|
||||
// Convert from degrees to milli degrees by multiplying by 10.
|
||||
// Will output 30250 milli degrees celsius for 30.25 degrees celsius
|
||||
temperature = 10 * ((tFine*5 + 128) >> 8)
|
||||
return
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in milli pascals (mPa).
|
||||
func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
// First 3 bytes are Pressure, last 3 bytes are Temperature
|
||||
data, err := d.readData(REG_PRES, 6)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rawTemp := convert3Bytes(data[3], data[4], data[5])
|
||||
|
||||
// Datasheet: 8.2 Compensation formula in 32 bit fixed point
|
||||
// Calculate tFine (temperature), used for the Pressure compensation
|
||||
var1 := ((rawTemp >> 3) - int32(d.cali.t1<<1)) * int32(d.cali.t2) >> 11
|
||||
var2 := (((rawTemp >> 4) - int32(d.cali.t1)) * ((rawTemp >> 4) - int32(d.cali.t1)) >> 12) *
|
||||
int32(d.cali.t3) >> 14
|
||||
|
||||
tFine := var1 + var2
|
||||
|
||||
rawPres := convert3Bytes(data[0], data[1], data[2])
|
||||
|
||||
// Datasheet: 8.2 Compensation formula in 32 bit fixed point
|
||||
// Pressure compensation
|
||||
var1 = (tFine >> 1) - 64000
|
||||
var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * int32(d.cali.p6)
|
||||
var2 = var2 + ((var1 * int32(d.cali.p5)) << 1)
|
||||
var2 = (var2 >> 2) + (int32(d.cali.p4) << 16)
|
||||
var1 = (((int32(d.cali.p3) * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) +
|
||||
((int32(d.cali.p2) * var1) >> 1)) >> 18
|
||||
var1 = ((32768 + var1) * int32(d.cali.p1)) >> 15
|
||||
|
||||
if var1 == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
p := uint32(((1048576 - rawPres) - (var2 >> 12)) * 3125)
|
||||
if p < 0x80000000 {
|
||||
p = (p << 1) / uint32(var1)
|
||||
} else {
|
||||
p = (p / uint32(var1)) * 2
|
||||
}
|
||||
|
||||
var1 = (int32(d.cali.p9) * int32(((p>>3)*(p>>3))>>13)) >> 12
|
||||
var2 = (int32(p>>2) * int32(d.cali.p8)) >> 13
|
||||
|
||||
return 1000 * (int32(p) + ((var1 + var2 + int32(d.cali.p7)) >> 4)), nil
|
||||
}
|
||||
|
||||
// readData reads n number of bytes of the specified register
|
||||
func (d *Device) readData(register int, n int) ([]byte, error) {
|
||||
// If not in normal mode, set the mode to FORCED mode, to prevent incorrect measurements
|
||||
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
|
||||
if d.Mode != MODE_NORMAL {
|
||||
config := uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(MODE_FORCED)
|
||||
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
||||
}
|
||||
|
||||
// Check STATUS register, wait if data is not available yet
|
||||
status := make([]byte, 1)
|
||||
for d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
|
||||
// Read the requested register
|
||||
data := make([]byte, n)
|
||||
err := d.bus.ReadRegister(uint8(d.Address), uint8(register), data[:])
|
||||
return data, err
|
||||
}
|
||||
|
||||
// convert3Bytes converts three bytes to int32
|
||||
func convert3Bytes(msb byte, b1 byte, lsb byte) int32 {
|
||||
return int32(((((uint32(msb) << 8) | uint32(b1)) << 8) | uint32(lsb)) >> 4)
|
||||
}
|
||||
|
||||
// readUint converts two bytes to uint16
|
||||
func readUint(msb byte, lsb byte) uint16 {
|
||||
return (uint16(msb) << 8) | uint16(lsb)
|
||||
}
|
||||
|
||||
// readUintLE converts two little endian bytes to uint16
|
||||
func readUintLE(msb byte, lsb byte) uint16 {
|
||||
temp := readUint(msb, lsb)
|
||||
return (temp >> 8) | (temp << 8)
|
||||
}
|
||||
|
||||
// readIntLE converts two little endian bytes to int16
|
||||
func readIntLE(msb byte, lsb byte) int16 {
|
||||
return int16(readUintLE(msb, lsb))
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Package bmp280 provides a driver for the BMP280 digital temperature & pressure sensor by Bosch.
|
||||
//
|
||||
// Datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
|
||||
package bmp280
|
||||
|
||||
// The I2C address which this device listens to.
|
||||
const Address = 0x77
|
||||
|
||||
// Registers
|
||||
const (
|
||||
REG_ID = 0xD0 // WHO_AM_I
|
||||
REG_RESET = 0xE0
|
||||
REG_STATUS = 0xF3
|
||||
REG_CTRL_MEAS = 0xF4
|
||||
REG_CONFIG = 0xF5
|
||||
REG_TEMP = 0xFA
|
||||
REG_PRES = 0xF7
|
||||
REG_CALI = 0x88
|
||||
|
||||
CHIP_ID = 0x58
|
||||
CMD_RESET = 0xB6
|
||||
)
|
||||
|
||||
const (
|
||||
SAMPLING_SKIPPED Oversampling = iota
|
||||
SAMPLING_1X
|
||||
SAMPLING_2X
|
||||
SAMPLING_4X
|
||||
SAMPLING_8X
|
||||
SAMPLING_16X
|
||||
)
|
||||
|
||||
const (
|
||||
MODE_SLEEP Mode = 0x00
|
||||
MODE_FORCED Mode = 0x01
|
||||
MODE_NORMAL Mode = 0x03
|
||||
)
|
||||
|
||||
const (
|
||||
STANDBY_1MS Standby = iota
|
||||
STANDBY_63MS
|
||||
STANDBY_125MS
|
||||
STANDBY_250MS
|
||||
STANDBY_500MS
|
||||
STANDBY_1000MS
|
||||
STANDBY_2000MS
|
||||
STANDBY_4000MS
|
||||
)
|
||||
|
||||
const (
|
||||
FILTER_OFF Filter = iota
|
||||
FILTER_2X
|
||||
FILTER_4X
|
||||
FILTER_8X
|
||||
FILTER_16X
|
||||
)
|
||||
@@ -0,0 +1,249 @@
|
||||
package bmp388
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
var (
|
||||
errConfigWrite = errors.New("bmp388: failed to configure sensor, check connection")
|
||||
errConfig = errors.New("bmp388: there is a problem with the configuration, try reducing ODR")
|
||||
errCaliRead = errors.New("bmp388: failed to read calibration coefficient register")
|
||||
errSoftReset = errors.New("bmp388: failed to perform a soft reset")
|
||||
errNotConnected = errors.New("bmp388: not connected")
|
||||
)
|
||||
|
||||
type Oversampling byte
|
||||
type Mode byte
|
||||
type OutputDataRate byte
|
||||
type FilterCoefficient byte
|
||||
|
||||
// Config contains settings for filtering, sampling, and modes of operation
|
||||
type Config struct {
|
||||
Pressure Oversampling
|
||||
Temperature Oversampling
|
||||
Mode Mode
|
||||
ODR OutputDataRate
|
||||
IIR FilterCoefficient
|
||||
}
|
||||
|
||||
// Device wraps the I2C connection and configuration values for the BMP388
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
cali calibrationCoefficients
|
||||
Config Config
|
||||
}
|
||||
|
||||
type calibrationCoefficients struct {
|
||||
// Temperature compensation
|
||||
t1 uint16
|
||||
t2 uint16
|
||||
t3 int8
|
||||
|
||||
// Pressure compensation
|
||||
p1 int16
|
||||
p2 int16
|
||||
p3 int8
|
||||
p4 int8
|
||||
p5 uint16
|
||||
p6 uint16
|
||||
p7 int8
|
||||
p8 int8
|
||||
p9 int16
|
||||
p10 int8
|
||||
p11 int8
|
||||
}
|
||||
|
||||
// New returns a bmp388 struct with the default I2C address. Configure must also be called after instanting
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure can enable settings on the BMP388 and reads the calibration coefficients
|
||||
func (d *Device) Configure(config Config) (err error) {
|
||||
d.Config = config
|
||||
|
||||
if d.Config == (Config{}) {
|
||||
d.Config.Mode = Normal
|
||||
}
|
||||
|
||||
// Turning on the pressure and temperature sensors and setting the measurement mode
|
||||
err = d.writeRegister(RegPwrCtrl, PwrPress|PwrTemp|byte(d.Config.Mode))
|
||||
|
||||
// Configure the oversampling, output data rate, and iir filter coefficient settings
|
||||
err = d.writeRegister(RegOSR, byte(d.Config.Pressure|d.Config.Temperature<<3))
|
||||
err = d.writeRegister(RegODR, byte(d.Config.ODR))
|
||||
err = d.writeRegister(RegIIR, byte(d.Config.IIR<<1))
|
||||
|
||||
if err != nil {
|
||||
return errConfigWrite
|
||||
}
|
||||
|
||||
// Check if there is a problem with the given configuration
|
||||
if d.configurationError() {
|
||||
return errConfig
|
||||
}
|
||||
|
||||
// Reading the builtin calibration coefficients and parsing them per the datasheet. The compensation formula given
|
||||
// in the datasheet is implemented in floating point
|
||||
buffer, err := d.readRegister(RegCali, 21)
|
||||
if err != nil {
|
||||
return errCaliRead
|
||||
}
|
||||
|
||||
d.cali.t1 = uint16(buffer[1])<<8 | uint16(buffer[0])
|
||||
d.cali.t2 = uint16(buffer[3])<<8 | uint16(buffer[2])
|
||||
d.cali.t3 = int8(buffer[4])
|
||||
|
||||
d.cali.p1 = int16(buffer[6])<<8 | int16(buffer[5])
|
||||
d.cali.p2 = int16(buffer[8])<<8 | int16(buffer[7])
|
||||
d.cali.p3 = int8(buffer[9])
|
||||
d.cali.p4 = int8(buffer[10])
|
||||
d.cali.p5 = uint16(buffer[12])<<8 | uint16(buffer[11])
|
||||
d.cali.p6 = uint16(buffer[14])<<8 | uint16(buffer[13])
|
||||
d.cali.p7 = int8(buffer[15])
|
||||
d.cali.p8 = int8(buffer[16])
|
||||
d.cali.p9 = int16(buffer[18])<<8 | int16(buffer[17])
|
||||
d.cali.p10 = int8(buffer[19])
|
||||
d.cali.p11 = int8(buffer[20])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the temperature registers and compute a compensation value for the temperature and pressure compensation
|
||||
// calculations. This is not the temperature itself.
|
||||
func (d *Device) tlinCompensate() (int64, error) {
|
||||
rawTemp, err := d.readSensorData(RegTemp)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// pulled from C driver: https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
|
||||
partialData1 := rawTemp - (256 * int64(d.cali.t1))
|
||||
partialData2 := int64(d.cali.t2) * partialData1
|
||||
partialData3 := (partialData1 * partialData1)
|
||||
partialData4 := partialData3 * int64(d.cali.t3)
|
||||
partialData5 := (partialData2 * 262144) + partialData4
|
||||
return partialData5 / 4294967296, nil
|
||||
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in centicelsius, i.e 2426 / 100 = 24.26 C
|
||||
func (d *Device) ReadTemperature() (int32, error) {
|
||||
|
||||
tlin, err := d.tlinCompensate()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
temp := (tlin * 25) / 16384
|
||||
return int32(temp), nil
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in centipascals, i.e 10132520 / 100 = 101325.20 Pa
|
||||
func (d *Device) ReadPressure() (int32, error) {
|
||||
|
||||
tlin, err := d.tlinCompensate()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rawPress, err := d.readSensorData(RegPress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// code pulled from bmp388 C driver: https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
|
||||
partialData1 := tlin * tlin
|
||||
partialData2 := partialData1 / 64
|
||||
partialData3 := (partialData2 * tlin) / 256
|
||||
partialData4 := (int64(d.cali.p8) * partialData3) / 32
|
||||
partialData5 := (int64(d.cali.p7) * partialData1) * 16
|
||||
partialData6 := (int64(d.cali.p6) * tlin) * 4194304
|
||||
offset := (int64(d.cali.p5) * 140737488355328) + partialData4 + partialData5 + partialData6
|
||||
partialData2 = (int64(d.cali.p4) * partialData3) / 32
|
||||
partialData4 = (int64(d.cali.p3) * partialData1) * 4
|
||||
partialData5 = (int64(d.cali.p2) - 16384) * tlin * 2097152
|
||||
sensitivity := ((int64(d.cali.p1) - 16384) * 70368744177664) + partialData2 + partialData4 + partialData5
|
||||
partialData1 = (sensitivity / 16777216) * rawPress
|
||||
partialData2 = int64(d.cali.p10) * tlin
|
||||
partialData3 = partialData2 + (65536 * int64(d.cali.p9))
|
||||
partialData4 = (partialData3 * rawPress) / 8192
|
||||
|
||||
// dividing by 10 followed by multiplying by 10
|
||||
// To avoid overflow caused by (pressure * partial_data4)
|
||||
partialData5 = (rawPress * (partialData4 / 10)) / 512
|
||||
partialData5 = partialData5 * 10
|
||||
partialData6 = (int64)(uint64(rawPress) * uint64(rawPress))
|
||||
partialData2 = (int64(d.cali.p11) * partialData6) / 65536
|
||||
partialData3 = (partialData2 * rawPress) / 128
|
||||
partialData4 = (offset / 4) + partialData1 + partialData5 + partialData3
|
||||
compPress := ((uint64(partialData4) * 25) / uint64(1099511627776))
|
||||
return int32(compPress), nil
|
||||
}
|
||||
|
||||
// SoftReset commands the BMP388 to reset of all user configuration settings
|
||||
func (d *Device) SoftReset() error {
|
||||
err := d.writeRegister(RegCmd, SoftReset)
|
||||
if err != nil {
|
||||
return errSoftReset
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connected tries to reach the bmp388 and check its chip id register. Returns true if it was able to successfully
|
||||
// communicate over i2c and returns the correct value
|
||||
func (d *Device) Connected() bool {
|
||||
data, err := d.readRegister(RegChipId, 1)
|
||||
return err == nil && data[0] == ChipId // returns true if i2c comm was good and response equals 0x50
|
||||
}
|
||||
|
||||
// SetMode changes the run mode of the sensor, NORMAL is the one to use for most cases. Use FORCED if you plan to take
|
||||
// measurements infrequently and want to conserve power. SLEEP will of course put the sensor to sleep
|
||||
func (d *Device) SetMode(mode Mode) error {
|
||||
d.Config.Mode = mode
|
||||
return d.writeRegister(RegPwrCtrl, PwrPress|PwrTemp|byte(d.Config.Mode))
|
||||
}
|
||||
|
||||
func (d *Device) readSensorData(register byte) (data int64, err error) {
|
||||
|
||||
if !d.Connected() {
|
||||
return 0, errNotConnected
|
||||
}
|
||||
|
||||
// put the sensor back into forced mode to get a reading, the sensor goes back to sleep after taking one read in
|
||||
// forced mode
|
||||
if d.Config.Mode != Normal {
|
||||
err = d.SetMode(Forced)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
bytes, err := d.readRegister(register, 3)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = int64(bytes[2])<<16 | int64(bytes[1])<<8 | int64(bytes[0])
|
||||
return
|
||||
}
|
||||
|
||||
// configurationError checks the register error for the configuration error bit. The bit is cleared on read by the bmp.
|
||||
func (d *Device) configurationError() bool {
|
||||
data, err := d.readRegister(RegErr, 1)
|
||||
return err == nil && (data[0]&0x04) != 0
|
||||
}
|
||||
|
||||
func (d *Device) readRegister(register byte, len int) (data []byte, err error) {
|
||||
data = make([]byte, len)
|
||||
err = d.bus.ReadRegister(d.Address, register, data)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Device) writeRegister(register byte, data byte) error {
|
||||
return d.bus.WriteRegister(d.Address, register, []byte{data})
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Package bmp388 provides a driver for Bosch's BMP388 digital temperature & pressure sensor.
|
||||
// The datasheet can be found here: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
|
||||
package bmp388
|
||||
|
||||
const Address byte = 0x77 // default I2C address
|
||||
|
||||
const (
|
||||
RegChipId byte = 0x00 // useful for checking the connection
|
||||
RegCali byte = 0x31 // pressure & temperature compensation calibration coefficients
|
||||
RegPress byte = 0x04 // start of pressure data registers
|
||||
RegTemp byte = 0x07 // start of temperature data registers
|
||||
RegPwrCtrl byte = 0x1B // measurement mode & pressure/temperature sensor power register
|
||||
RegOSR byte = 0x1C // oversampling settings register
|
||||
RegODR byte = 0x1D //
|
||||
RegCmd byte = 0x7E // miscellaneous command register
|
||||
RegStat byte = 0x03 // sensor status register
|
||||
RegErr byte = 0x02 // error status register
|
||||
RegIIR byte = 0x1F
|
||||
)
|
||||
|
||||
const (
|
||||
ChipId byte = 0x50 // correct response if reading from chip id register
|
||||
PwrPress byte = 0x01 // power on pressure sensor
|
||||
PwrTemp byte = 0x02 // power on temperature sensor
|
||||
SoftReset byte = 0xB6 // command to reset all user configuration
|
||||
DRDYPress byte = 0x20 // for checking if pressure data is ready
|
||||
DRDYTemp byte = 0x40 // for checking if pressure data is ready
|
||||
)
|
||||
|
||||
// The difference between forced and normal mode is the bmp388 goes to sleep after taking a measurement in forced mode.
|
||||
// Set it to forced if you intend to take measurements sporadically and want to save power. The driver will handle
|
||||
// waking the sensor up when the sensor is in forced mode.
|
||||
const (
|
||||
Normal Mode = 0x30
|
||||
Forced Mode = 0x16
|
||||
Sleep Mode = 0x00
|
||||
)
|
||||
|
||||
// Increasing sampling rate increases precision but also the wait time for measurements. The datasheet has a table of
|
||||
// suggested values for oversampling, output data rates, and iir filter coefficients by use case.
|
||||
const (
|
||||
Sampling1X Oversampling = iota
|
||||
Sampling2X
|
||||
Sampling4X
|
||||
Sampling8X
|
||||
Sampling16X
|
||||
Sampling32X
|
||||
)
|
||||
|
||||
// Output data rates in Hz. If increasing the sampling rates you need to decrease the output data rates, else the bmp388
|
||||
// will freeze and Configure() will return a configuration error message. In that case keep decreasing the data rate
|
||||
// until the bmp is happy
|
||||
const (
|
||||
Odr200 OutputDataRate = iota
|
||||
Odr100
|
||||
Odr50
|
||||
Odr25
|
||||
Odr12p5
|
||||
Odr6p25
|
||||
Odr3p1
|
||||
Odr1p5
|
||||
Odr0p78
|
||||
Odr0p39
|
||||
Odr0p2
|
||||
Odr0p1
|
||||
Odr0p05
|
||||
Odr0p02
|
||||
Odr0p01
|
||||
Odr0p006
|
||||
Odr0p003
|
||||
Odr0p0015
|
||||
)
|
||||
|
||||
// IIR filter coefficients, higher values means steadier measurements but slower reaction times
|
||||
const (
|
||||
Coeff0 FilterCoefficient = iota
|
||||
Coeff1
|
||||
Coeff3
|
||||
Coeff7
|
||||
Coeff15
|
||||
Coeff31
|
||||
Coeff63
|
||||
Coeff127
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// See ../../image/README.md for the usage.
|
||||
|
||||
func main() {
|
||||
err := run(os.Args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(args []string) error {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("usage: %s FILE")
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("const %s = \"\" +\n", strings.Replace(args[1], ".", "_", -1))
|
||||
|
||||
i := 0
|
||||
max := 32
|
||||
for i = 0; i < len(b); i++ {
|
||||
bb := b[i]
|
||||
if (i % max) == 0 {
|
||||
fmt.Printf(" \"")
|
||||
}
|
||||
fmt.Printf("\\x%02X", bb)
|
||||
if (i%max) == max-1 && i != len(b)-1 {
|
||||
fmt.Printf("\" + \n")
|
||||
}
|
||||
}
|
||||
if (i % max) < max-1 {
|
||||
fmt.Printf("\"\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// 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
|
||||
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
|
||||
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
|
||||
|
||||
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
|
||||
|
||||
func (t TemperatureScale) convertToFloat(temp int16) float32 {
|
||||
if t == C {
|
||||
return float32(temp) / 10
|
||||
} else {
|
||||
// Fahrenheit
|
||||
return float32(temp)*(9.0/50.) + 32.
|
||||
}
|
||||
}
|
||||
|
||||
// All functions return ErrorCode instance as error. This class can be used for more efficient error processing
|
||||
type ErrorCode uint8
|
||||
|
||||
const (
|
||||
startTimeout = time.Millisecond * 200
|
||||
startingLow = time.Millisecond * 20
|
||||
|
||||
DHT11 DeviceType = iota
|
||||
DHT22
|
||||
|
||||
C TemperatureScale = iota
|
||||
F
|
||||
|
||||
ChecksumError ErrorCode = iota
|
||||
NoSignalError
|
||||
NoDataError
|
||||
UpdateError
|
||||
UninitializedDataError
|
||||
)
|
||||
|
||||
// error interface implementation for ErrorCode
|
||||
func (e ErrorCode) Error() string {
|
||||
switch e {
|
||||
case ChecksumError:
|
||||
// DHT returns ChecksumError if all the data from the sensor was received, but the checksum does not match.
|
||||
return "checksum mismatch"
|
||||
case NoSignalError:
|
||||
// DHT returns NoSignalError if there was no reply from the sensor. Check sensor connection or the correct pin
|
||||
// sis chosen,
|
||||
return "no signal"
|
||||
case NoDataError:
|
||||
// DHT returns NoDataError if the connection was successfully initialized, but not all 40 bits from
|
||||
// the sensor is received
|
||||
return "no data"
|
||||
case UpdateError:
|
||||
// DHT returns UpdateError if ReadMeasurements function is called before time specified in UpdatePolicy or
|
||||
// less than 2 seconds after past measurement
|
||||
return "cannot update now"
|
||||
case UninitializedDataError:
|
||||
// DHT returns UninitializedDataError if user attempts to access data before first measurement
|
||||
return "no measurements done"
|
||||
}
|
||||
// should never be reached
|
||||
return "unknown error"
|
||||
}
|
||||
|
||||
// Update policy of the DHT device. UpdateTime cannot be shorter than 2 seconds. According to dht specification sensor
|
||||
// will return undefined data if update requested less than 2 seconds before last usage
|
||||
type UpdatePolicy struct {
|
||||
UpdateTime time.Duration
|
||||
UpdateAutomatically bool
|
||||
}
|
||||
|
||||
var (
|
||||
// timeout counter equal to number of ticks per 1 millisecond
|
||||
timeout counter
|
||||
)
|
||||
|
||||
func init() {
|
||||
timeout = cyclesPerMillisecond()
|
||||
}
|
||||
|
||||
func cyclesPerMillisecond() counter {
|
||||
freq := machine.CPUFrequency()
|
||||
freq /= 1000
|
||||
return counter(freq)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build mimxrt1062 || stm32f405 || atsamd51 || stm32f103xx || k210 || stm32f407
|
||||
// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
// This file provides a definition of the counter for boards with frequency higher than 2^8 ticks per millisecond (>64MHz)
|
||||
type counter uint32
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build !mimxrt1062 && !stm32f405 && !atsamd51 && !stm32f103xx && !k210 && !stm32f407
|
||||
// +build !mimxrt1062,!stm32f405,!atsamd51,!stm32f103xx,!k210,!stm32f407
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
// This file provides a definition of the counter for boards with frequency lower than 2^8 ticks per millisecond (<64MHz)
|
||||
type counter uint16
|
||||
@@ -0,0 +1,218 @@
|
||||
// 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
|
||||
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
|
||||
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DummyDevice provides a basic interface for DHT devices.
|
||||
type DummyDevice interface {
|
||||
ReadMeasurements() error
|
||||
Measurements() (temperature int16, humidity uint16, err error)
|
||||
Temperature() (int16, error)
|
||||
TemperatureFloat(scale TemperatureScale) (float32, error)
|
||||
Humidity() (uint16, error)
|
||||
HumidityFloat() (float32, error)
|
||||
}
|
||||
|
||||
// Basic implementation of the DummyDevice
|
||||
// This implementation takes measurements from sensor only with ReadMeasurements function
|
||||
// and does not provide a protection from too frequent calls for measurements.
|
||||
// Since taking measurements from the sensor is time consuming procedure and blocks interrupts,
|
||||
// user can avoid any hidden calls to the sensor.
|
||||
type device struct {
|
||||
pin machine.Pin
|
||||
|
||||
measurements DeviceType
|
||||
initialized bool
|
||||
|
||||
temperature int16
|
||||
humidity uint16
|
||||
}
|
||||
|
||||
// ReadMeasurements reads data from the sensor.
|
||||
// According to documentation pin should be always, but the t *device restores pin to the state before call.
|
||||
func (t *device) ReadMeasurements() error {
|
||||
// initial waiting
|
||||
state := powerUp(t.pin)
|
||||
defer t.pin.Set(state)
|
||||
err := t.read()
|
||||
if err == nil {
|
||||
t.initialized = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Getter for temperature. Temperature method returns temperature as it is sent by device.
|
||||
// The temperature is measured temperature in Celsius multiplied by 10.
|
||||
// If no successful measurements for this device was performed, returns UninitializedDataError.
|
||||
func (t *device) Temperature() (int16, error) {
|
||||
if !t.initialized {
|
||||
return 0, UninitializedDataError
|
||||
}
|
||||
return t.temperature, nil
|
||||
}
|
||||
|
||||
// Getter for temperature. TemperatureFloat returns temperature in a given scale.
|
||||
// If no successful measurements for this device was performed, returns UninitializedDataError.
|
||||
func (t *device) TemperatureFloat(scale TemperatureScale) (float32, error) {
|
||||
if !t.initialized {
|
||||
return 0, UninitializedDataError
|
||||
}
|
||||
return scale.convertToFloat(t.temperature), nil
|
||||
}
|
||||
|
||||
// Getter for humidity. Humidity returns humidity as it is sent by device.
|
||||
// The humidity is measured in percentages multiplied by 10.
|
||||
// If no successful measurements for this device was performed, returns UninitializedDataError.
|
||||
func (t *device) Humidity() (uint16, error) {
|
||||
if !t.initialized {
|
||||
return 0, UninitializedDataError
|
||||
}
|
||||
return t.humidity, nil
|
||||
}
|
||||
|
||||
// Getter for humidity. HumidityFloat returns humidity in percentages.
|
||||
// If no successful measurements for this device was performed, returns UninitializedDataError.
|
||||
func (t *device) HumidityFloat() (float32, error) {
|
||||
if !t.initialized {
|
||||
return 0, UninitializedDataError
|
||||
}
|
||||
return float32(t.humidity) / 10., nil
|
||||
}
|
||||
|
||||
// Perform initialization of the communication protocol.
|
||||
// Device lowers the voltage on pin for startingLow=20ms and starts listening for response
|
||||
// Section 5.2 in [1]
|
||||
func initiateCommunication(p machine.Pin) {
|
||||
// Send low signal to the device
|
||||
p.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
p.Low()
|
||||
time.Sleep(startingLow)
|
||||
// Set pin to high and wait for reply
|
||||
p.High()
|
||||
p.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
}
|
||||
|
||||
// Measurements returns both measurements: temperature and humidity as they sent by the device.
|
||||
// If no successful measurements for this device was performed, returns UninitializedDataError.
|
||||
func (t *device) Measurements() (temperature int16, humidity uint16, err error) {
|
||||
if !t.initialized {
|
||||
return 0, 0, UninitializedDataError
|
||||
}
|
||||
temperature = t.temperature
|
||||
humidity = t.humidity
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Main routine that performs communication with the sensor
|
||||
func (t *device) read() error {
|
||||
// initialize loop variables
|
||||
|
||||
// buffer for the data sent by the sensor. Sensor sends 40 bits = 5 bytes
|
||||
bufferData := [5]byte{}
|
||||
buf := bufferData[:]
|
||||
|
||||
// We perform measurements of the signal from the sensor by counting low and high cycles.
|
||||
// The bit is determined by the relative length of the high signal to low signal.
|
||||
// For 1, high signal will be longer than low, for 0---low is longer.
|
||||
// See section 5.3 [1]
|
||||
signalsData := [80]counter{}
|
||||
signals := signalsData[:]
|
||||
|
||||
// Start communication protocol with sensor
|
||||
initiateCommunication(t.pin)
|
||||
// Wait for sensor's response and abort if sensor does not reply
|
||||
err := waitForDataTransmission(t.pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// count low and high cycles for sensor's reply
|
||||
receiveSignals(t.pin, signals)
|
||||
|
||||
// process received signals and store the result in the buffer. Abort if data transmission was interrupted and not
|
||||
// all 40 bits were received
|
||||
err = t.extractData(signals[:], buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Compute checksum and compare it to the one in data. Abort if checksum is incorrect
|
||||
if !isValid(buf[:]) {
|
||||
return ChecksumError
|
||||
}
|
||||
|
||||
// Extract temperature and humidity data from buffer
|
||||
t.temperature, t.humidity = t.measurements.extractData(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
// receiveSignals counts number of low and high cycles. The execution is time critical, so the function disables
|
||||
// interrupts
|
||||
func receiveSignals(pin machine.Pin, result []counter) {
|
||||
i := uint8(0)
|
||||
machine.UART1.Interrupt.Disable()
|
||||
defer machine.UART1.Interrupt.Enable()
|
||||
for ; i < 40; i++ {
|
||||
result[i*2] = expectChange(pin, false)
|
||||
result[i*2+1] = expectChange(pin, true)
|
||||
}
|
||||
}
|
||||
|
||||
// extractData process signal counters and transforms them into bits.
|
||||
// if any of the bits were not received (timed-out), returns NoDataError
|
||||
func (t *device) extractData(signals []counter, buf []uint8) error {
|
||||
for i := uint8(0); i < 40; i++ {
|
||||
lowCycle := signals[i*2]
|
||||
highCycle := signals[i*2+1]
|
||||
if lowCycle == timeout || highCycle == timeout {
|
||||
return NoDataError
|
||||
}
|
||||
byteN := i >> 3
|
||||
buf[byteN] <<= 1
|
||||
if highCycle > lowCycle {
|
||||
buf[byteN] |= 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitForDataTransmission waits for reply from the sensor.
|
||||
// If no reply received, returns NoSignalError.
|
||||
// For more details, see section 5.2 in [1]
|
||||
func waitForDataTransmission(p machine.Pin) error {
|
||||
// wait for thermometer to pull down
|
||||
if expectChange(p, true) == timeout {
|
||||
return NoSignalError
|
||||
}
|
||||
//wait for thermometer to pull up
|
||||
if expectChange(p, false) == timeout {
|
||||
return NoSignalError
|
||||
}
|
||||
// wait for thermometer to pull down and start sending the data
|
||||
if expectChange(p, true) == timeout {
|
||||
return NoSignalError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Constructor function for a DummyDevice implementation.
|
||||
// This device provides full control to the user.
|
||||
// It does not do any hidden measurements calls and does not check
|
||||
// for 2 seconds delay between measurements.
|
||||
func NewDummyDevice(pin machine.Pin, deviceType DeviceType) DummyDevice {
|
||||
pin.High()
|
||||
return &device{
|
||||
pin: pin,
|
||||
measurements: deviceType,
|
||||
initialized: false,
|
||||
temperature: 0,
|
||||
humidity: 0,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// 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
|
||||
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
|
||||
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Device interface provides main functionality of the DHTXX sensors.
|
||||
type Device interface {
|
||||
DummyDevice
|
||||
Configure(policy UpdatePolicy)
|
||||
}
|
||||
|
||||
// managedDevice struct provides time control and optional automatic data retrieval from the sensor.
|
||||
// It delegates all the functionality to device
|
||||
type managedDevice struct {
|
||||
t device
|
||||
lastUpdate time.Time
|
||||
policy UpdatePolicy
|
||||
}
|
||||
|
||||
// Measurements returns both measurements: temperature and humidity as they sent by the device.
|
||||
// Depending on the UpdatePolicy of the device may update cached measurements.
|
||||
func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) {
|
||||
err = m.checkForUpdateOnDataRequest()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return m.t.Measurements()
|
||||
}
|
||||
|
||||
// Getter for temperature. Temperature method returns temperature as it is sent by device.
|
||||
// The temperature is measured temperature in Celsius multiplied by 10.
|
||||
// Depending on the UpdatePolicy of the device may update cached measurements.
|
||||
func (m *managedDevice) Temperature() (temp int16, err error) {
|
||||
err = m.checkForUpdateOnDataRequest()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
temp, err = m.t.Temperature()
|
||||
return
|
||||
}
|
||||
|
||||
func (m *managedDevice) checkForUpdateOnDataRequest() (err error) {
|
||||
// update if necessary
|
||||
if m.policy.UpdateAutomatically {
|
||||
err = m.ReadMeasurements()
|
||||
}
|
||||
// ignore error if the data was updated recently
|
||||
// interface comparison does not work in tinygo. Therefore need to cast to explicit type
|
||||
if code, ok := err.(ErrorCode); ok && code == UpdateError {
|
||||
err = nil
|
||||
}
|
||||
// add error if the data is not initialized
|
||||
if !m.t.initialized {
|
||||
err = UninitializedDataError
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Getter for temperature. TemperatureFloat returns temperature in a given scale.
|
||||
// Depending on the UpdatePolicy of the device may update cached measurements.
|
||||
func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) {
|
||||
err := m.checkForUpdateOnDataRequest()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.t.TemperatureFloat(scale)
|
||||
}
|
||||
|
||||
// Getter for humidity. Humidity returns humidity as it is sent by device.
|
||||
// The humidity is measured in percentages multiplied by 10.
|
||||
// Depending on the UpdatePolicy of the device may update cached measurements.
|
||||
func (m *managedDevice) Humidity() (hum uint16, err error) {
|
||||
err = m.checkForUpdateOnDataRequest()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.t.Humidity()
|
||||
}
|
||||
|
||||
// Getter for humidity. HumidityFloat returns humidity in percentages.
|
||||
// Depending on the UpdatePolicy of the device may update cached measurements.
|
||||
func (m *managedDevice) HumidityFloat() (float32, error) {
|
||||
err := m.checkForUpdateOnDataRequest()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.t.HumidityFloat()
|
||||
}
|
||||
|
||||
// ReadMeasurements reads data from the sensor.
|
||||
// The function will return UpdateError if it is called more frequently than specified in UpdatePolicy
|
||||
func (m *managedDevice) ReadMeasurements() (err error) {
|
||||
timestamp := time.Now()
|
||||
if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime {
|
||||
err = m.t.ReadMeasurements()
|
||||
} else {
|
||||
err = UpdateError
|
||||
}
|
||||
if err == nil {
|
||||
m.lastUpdate = timestamp
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Configure configures UpdatePolicy for Device.
|
||||
// Configure checks for policy.UpdateTime and prevent from updating more frequently than specified in [1][2]
|
||||
// to prevent undefined behaviour of the sensor.
|
||||
func (m *managedDevice) Configure(policy UpdatePolicy) {
|
||||
if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 {
|
||||
policy.UpdateTime = time.Second * 2
|
||||
}
|
||||
m.policy = policy
|
||||
}
|
||||
|
||||
// Constructor of the Device implementation.
|
||||
// This implementation updates data every 2 seconds during data access.
|
||||
func New(pin machine.Pin, deviceType DeviceType) Device {
|
||||
pin.High()
|
||||
return &managedDevice{
|
||||
t: device{
|
||||
pin: pin,
|
||||
measurements: deviceType,
|
||||
initialized: false,
|
||||
},
|
||||
lastUpdate: time.Time{},
|
||||
policy: UpdatePolicy{
|
||||
UpdateTime: time.Second * 2,
|
||||
UpdateAutomatically: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor of the Device implementation with given UpdatePolicy
|
||||
func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device {
|
||||
pin.High()
|
||||
result := &managedDevice{
|
||||
t: device{
|
||||
pin: pin,
|
||||
measurements: deviceType,
|
||||
initialized: false,
|
||||
},
|
||||
lastUpdate: time.Time{},
|
||||
}
|
||||
result.Configure(updatePolicy)
|
||||
return result
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Check if the pin is disabled
|
||||
func powerUp(p machine.Pin) bool {
|
||||
state := p.Get()
|
||||
if !state {
|
||||
p.High()
|
||||
time.Sleep(startTimeout)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func expectChange(p machine.Pin, oldState bool) counter {
|
||||
cnt := counter(0)
|
||||
for ; p.Get() == oldState && cnt != timeout; cnt++ {
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
func checksum(buf []uint8) uint8 {
|
||||
return buf[4]
|
||||
}
|
||||
func computeChecksum(buf []uint8) uint8 {
|
||||
return buf[0] + buf[1] + buf[2] + buf[3]
|
||||
}
|
||||
|
||||
func isValid(buf []uint8) bool {
|
||||
return checksum(buf) == computeChecksum(buf)
|
||||
}
|
||||
+5
-5
@@ -9,18 +9,18 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a DS1307 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
AddressSRAM uint8
|
||||
}
|
||||
|
||||
// New creates a new DS1307 connection. I2C bus must be already configured.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus,
|
||||
Address: uint8(I2CAddress),
|
||||
AddressSRAM: SRAMBeginAddres,
|
||||
@@ -42,8 +42,8 @@ func (d *Device) SetTime(t time.Time) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Time returns the time and date
|
||||
func (d *Device) Time() (time.Time, error) {
|
||||
// ReadTime returns the date and time
|
||||
func (d *Device) ReadTime() (time.Time, error) {
|
||||
data := make([]byte, 8)
|
||||
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
|
||||
if err != nil {
|
||||
|
||||
+4
-3
@@ -5,15 +5,16 @@
|
||||
package ds3231 // import "tinygo.org/x/drivers/ds3231"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type Mode uint8
|
||||
|
||||
// Device wraps an I2C connection to a DS3231 device.
|
||||
type Device struct {
|
||||
bus machine.I2C
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
}
|
||||
|
||||
@@ -21,7 +22,7 @@ type Device struct {
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus machine.I2C) Device {
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
|
||||
+3
-3
@@ -20,17 +20,17 @@ package espat // import "tinygo.org/x/drivers/espat"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
// Device wraps UART connection to the ESP8266/ESP32.
|
||||
type Device struct {
|
||||
bus machine.UART
|
||||
bus drivers.UART
|
||||
|
||||
// command responses that come back from the ESP8266/ESP32
|
||||
response []byte
|
||||
@@ -43,7 +43,7 @@ type Device struct {
|
||||
var ActiveDevice *Device
|
||||
|
||||
// New returns a new espat driver. Pass in a fully configured UART bus.
|
||||
func New(b machine.UART) *Device {
|
||||
func New(b drivers.UART) *Device {
|
||||
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = &machine.I2C0
|
||||
sensor = adt7410.New(i2c, 0)
|
||||
i2c = machine.I2C0
|
||||
sensor = adt7410.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/aht20"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
dev := aht20.New(machine.I2C0)
|
||||
dev.Configure()
|
||||
|
||||
dev.Reset()
|
||||
for {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
err := dev.Read()
|
||||
if err != nil {
|
||||
println("Error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
println("temp ", fmtD(dev.DeciCelsius(), 3, 1), "C")
|
||||
println("humidity", fmtD(dev.DeciRelHumidity(), 3, 1), "%")
|
||||
}
|
||||
}
|
||||
|
||||
func fmtD(val int32, i int, f int) string {
|
||||
result := make([]byte, i+f+1)
|
||||
neg := false
|
||||
|
||||
if val < 0 {
|
||||
val = -val
|
||||
neg = true
|
||||
}
|
||||
|
||||
for p := len(result) - 1; p >= 0; p-- {
|
||||
result[p] = byte(int32('0') + (val % 10))
|
||||
val = val / 10
|
||||
|
||||
if p == i+1 && p > 0 {
|
||||
p--
|
||||
result[p] = '.'
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
result[0] = '-'
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
||||
@@ -13,8 +13,8 @@ func main() {
|
||||
|
||||
machine.SPI1.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI1_SCK_PIN,
|
||||
MOSI: machine.SPI1_MOSI_PIN,
|
||||
MISO: machine.SPI1_MISO_PIN,
|
||||
SDO: machine.SPI1_SDO_PIN,
|
||||
SDI: machine.SPI1_SDI_PIN,
|
||||
Frequency: 8000000,
|
||||
})
|
||||
machine.I2C0.Configure(machine.I2CConfig{SCL: machine.SCL_PIN, SDA: machine.SDA_PIN})
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
apa apa102.Device
|
||||
apa *apa102.Device
|
||||
|
||||
led = machine.PWM{machine.LED}
|
||||
pwm = machine.TCC0
|
||||
leds = make([]color.RGBA, 1)
|
||||
wheel = &Wheel{Brightness: 0x10}
|
||||
)
|
||||
@@ -27,12 +27,19 @@ func init() {
|
||||
apa = apa102.NewSoftwareSPI(machine.PA00, machine.PA01, 1)
|
||||
|
||||
// Configure the regular on-board LED for PWM fading
|
||||
machine.InitPWM()
|
||||
led.Configure()
|
||||
|
||||
err := pwm.Configure(machine.PWMConfig{})
|
||||
if err != nil {
|
||||
println("failed to configure PWM")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
channelLED, err := pwm.Channel(machine.LED)
|
||||
if err != nil {
|
||||
println("failed to configure LED PWM channel")
|
||||
return
|
||||
}
|
||||
|
||||
// We'll fade the on-board LED in a goroutine to show/ensure that the APA102
|
||||
// works fine with the scheduler enabled. Comment this out to test this code
|
||||
@@ -43,11 +50,11 @@ func main() {
|
||||
brightening = !brightening
|
||||
continue
|
||||
}
|
||||
var brightness uint16 = uint16(i) << 8
|
||||
var brightness uint32 = uint32(i)
|
||||
if !brightening {
|
||||
brightness = 0xFFFF - brightness
|
||||
brightness = 256 - brightness
|
||||
}
|
||||
led.Set(brightness)
|
||||
pwm.Set(channelLED, pwm.Top()*brightness/256)
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableColor() // enable color engine
|
||||
|
||||
for {
|
||||
|
||||
if sensor.ColorAvailable() {
|
||||
r, g, b, c := sensor.ReadColor()
|
||||
println("Red =", r, "\tGreen =", g, "\tBlue =", b, "\tClear =", c)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableGesture() // enable gesture engine
|
||||
|
||||
for {
|
||||
|
||||
// wave your hand (not too slow) about 10 cm above the sensor
|
||||
if sensor.GestureAvailable() {
|
||||
|
||||
gesture := sensor.ReadGesture()
|
||||
print("Detected gesture: ")
|
||||
switch gesture {
|
||||
case apds9960.GESTURE_UP:
|
||||
println("Up")
|
||||
case apds9960.GESTURE_DOWN:
|
||||
println("Down")
|
||||
case apds9960.GESTURE_LEFT:
|
||||
println("Left")
|
||||
case apds9960.GESTURE_RIGHT:
|
||||
println("Right")
|
||||
}
|
||||
}
|
||||
// note: the delay shouldn't be too long, otherwise new gesture data might be lost
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableProximity() // enable proximity engine
|
||||
|
||||
for {
|
||||
|
||||
if sensor.ProximityAvailable() {
|
||||
p := sensor.ReadProximity()
|
||||
println("Proximity:", p)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
|
||||
for {
|
||||
led.Low()
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
led.High()
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
"tinygo.org/x/drivers/bmi160"
|
||||
)
|
||||
|
||||
func main() {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
machine.SPI0.Configure(machine.SPIConfig{})
|
||||
sensor := bmi160.NewSPI(machine.A5, machine.SPI0)
|
||||
sensor.Configure()
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("BMI160 not connected")
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
t, err := sensor.ReadTemperature()
|
||||
if err != nil {
|
||||
println("Error reading temperature", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Temperature: %.2f °C\n", float32(t)/1000)
|
||||
|
||||
accelX, accelY, accelZ, err := sensor.ReadAcceleration()
|
||||
if err != nil {
|
||||
println("Error reading acceleration", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Acceleration: %.2fg %.2fg %.2fg\n", float32(accelX)/1e6, float32(accelY)/1e6, float32(accelZ)/1e6)
|
||||
|
||||
gyroX, gyroY, gyroZ, err := sensor.ReadRotation()
|
||||
if err != nil {
|
||||
println("Error reading rotation", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Rotation: %.2f°/s %.2f°/s %.2f°/s\n", float32(gyroX)/1e6, float32(gyroY)/1e6, float32(gyroZ)/1e6)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
"tinygo.org/x/drivers/bmp280"
|
||||
)
|
||||
|
||||
func main() {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
sensor := bmp280.New(machine.I2C0)
|
||||
sensor.Configure(bmp280.STANDBY_125MS, bmp280.FILTER_4X, bmp280.SAMPLING_16X, bmp280.SAMPLING_16X, bmp280.MODE_FORCED)
|
||||
|
||||
connected := sensor.Connected()
|
||||
if !connected {
|
||||
println("\nBMP280 Sensor not detected\n")
|
||||
return
|
||||
}
|
||||
println("\nBMP280 Sensor detected\n")
|
||||
|
||||
println("Calibration:")
|
||||
sensor.PrintCali()
|
||||
|
||||
for {
|
||||
t, err := sensor.ReadTemperature()
|
||||
if err != nil {
|
||||
println("Error reading temperature")
|
||||
}
|
||||
// Temperature in degrees Celsius
|
||||
fmt.Printf("Temperature: %.2f °C\n", float32(t)/1000)
|
||||
|
||||
p, err := sensor.ReadPressure()
|
||||
if err != nil {
|
||||
println("Error reading pressure")
|
||||
}
|
||||
// Pressure in hectoPascal
|
||||
fmt.Printf("Pressure: %.2f hPa\n", float32(p)/100000)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/bmp388"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
sensor := bmp388.New(machine.I2C0)
|
||||
if !sensor.Connected() {
|
||||
println("Uh oh, BMP388 not detected")
|
||||
return
|
||||
}
|
||||
|
||||
// The accuracy of the sensor can be increased, at the cost of a slower output rate. Table 9 in Section 3.5 of the
|
||||
// datasheet has recommended settings for common use cases. If increasing the sampling rate, the output data rate
|
||||
// (ODR) will likely have to be decreased. Configure() will return an error if there's a problem with the
|
||||
// configuration settings - keep decreasing the ODR and cycling the power to the sensor until it is happy.
|
||||
err := sensor.Configure(bmp388.Config{
|
||||
Pressure: bmp388.Sampling8X,
|
||||
Temperature: bmp388.Sampling2X,
|
||||
ODR: bmp388.Odr25,
|
||||
IIR: bmp388.Coeff0,
|
||||
Mode: bmp388.Normal,
|
||||
})
|
||||
|
||||
// This is also fine
|
||||
// err := sensor.Configure(bmp388.BMP388Config{})
|
||||
|
||||
if err != nil {
|
||||
println(err)
|
||||
}
|
||||
|
||||
for {
|
||||
temp, err := sensor.ReadTemperature() // returns the temperature in centicelsius
|
||||
press, err := sensor.ReadPressure() // returns the pressure in centipascals
|
||||
|
||||
if err != nil {
|
||||
println(err)
|
||||
} else {
|
||||
println("Temperature: " + strconv.FormatInt(int64(temp), 10) + " cC")
|
||||
println("Pressure: " + strconv.FormatInt(int64(press), 10) + " cPa\n")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
"tinygo.org/x/drivers/dht"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pin := machine.D6
|
||||
dhtSensor := dht.New(pin, dht.DHT11)
|
||||
for {
|
||||
temp, hum, err := dhtSensor.Measurements()
|
||||
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())
|
||||
}
|
||||
// Measurements cannot be updated only 2 seconds. More frequent calls will return the same value
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ func main() {
|
||||
rtc.SetTime(time.Date(2019, 5, 15, 20, 34, 12, 0, time.UTC))
|
||||
|
||||
for {
|
||||
t, err := rtc.Time()
|
||||
t, err := rtc.ReadTime()
|
||||
if err != nil {
|
||||
println("Error reading date:", err)
|
||||
break
|
||||
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
console = machine.UART0
|
||||
console = machine.Serial
|
||||
|
||||
adaptor *espat.Device
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ var (
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
console = machine.UART0
|
||||
console = machine.Serial
|
||||
|
||||
adaptor *espat.Device
|
||||
topic = "tinygo"
|
||||
|
||||
@@ -37,7 +37,7 @@ var (
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
console = machine.UART0
|
||||
console = machine.Serial
|
||||
|
||||
adaptor *espat.Device
|
||||
cl mqtt.Client
|
||||
|
||||
@@ -20,7 +20,7 @@ var (
|
||||
input [consoleBufLen]byte
|
||||
store [storageBufLen]byte
|
||||
|
||||
console = machine.UART0
|
||||
console = machine.Serial
|
||||
|
||||
dev *flash.Device
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/examples/flash/console"
|
||||
console_example "tinygo.org/x/drivers/examples/flash/console"
|
||||
"tinygo.org/x/drivers/flash"
|
||||
)
|
||||
|
||||
@@ -11,8 +11,8 @@ func main() {
|
||||
console_example.RunFor(
|
||||
flash.NewSPI(
|
||||
&machine.SPI1,
|
||||
machine.SPI1_MOSI_PIN,
|
||||
machine.SPI1_MISO_PIN,
|
||||
machine.SPI1_SDO_PIN,
|
||||
machine.SPI1_SDI_PIN,
|
||||
machine.SPI1_SCK_PIN,
|
||||
machine.SPI1_CS_PIN,
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/gps"
|
||||
)
|
||||
@@ -10,20 +10,41 @@ import (
|
||||
func main() {
|
||||
println("GPS I2C Example")
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
ublox := gps.NewI2C(&machine.I2C0)
|
||||
parser := gps.Parser(ublox)
|
||||
ublox := gps.NewI2C(machine.I2C0)
|
||||
parser := gps.NewParser()
|
||||
var fix gps.Fix
|
||||
for {
|
||||
fix = parser.NextFix()
|
||||
s, err := ublox.NextSentence()
|
||||
if err != nil {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
fix, err = parser.Parse(s)
|
||||
if err != nil {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
if fix.Valid {
|
||||
print(fix.Time.Format("15:04:05"))
|
||||
print(", lat=", fmt.Sprintf("%f", fix.Latitude))
|
||||
print(", long=", fmt.Sprintf("%f", fix.Longitude))
|
||||
print(", altitude:=", fix.Altitude)
|
||||
print(", lat=")
|
||||
print(fix.Latitude)
|
||||
print(", long=")
|
||||
print(fix.Longitude)
|
||||
print(", altitude=", fix.Altitude)
|
||||
print(", satellites=", fix.Satellites)
|
||||
if fix.Speed != 0 {
|
||||
print(", speed=")
|
||||
print(fix.Speed)
|
||||
}
|
||||
if fix.Heading != 0 {
|
||||
print(", heading=")
|
||||
print(fix.Heading)
|
||||
}
|
||||
println()
|
||||
} else {
|
||||
println("No fix")
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/gps"
|
||||
)
|
||||
@@ -10,20 +10,41 @@ import (
|
||||
func main() {
|
||||
println("GPS UART Example")
|
||||
machine.UART1.Configure(machine.UARTConfig{BaudRate: 9600})
|
||||
ublox := gps.NewUART(&machine.UART1)
|
||||
parser := gps.Parser(ublox)
|
||||
ublox := gps.NewUART(machine.UART1)
|
||||
parser := gps.NewParser()
|
||||
var fix gps.Fix
|
||||
for {
|
||||
fix = parser.NextFix()
|
||||
s, err := ublox.NextSentence()
|
||||
if err != nil {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
fix, err = parser.Parse(s)
|
||||
if err != nil {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
if fix.Valid {
|
||||
print(fix.Time.Format("15:04:05"))
|
||||
print(", lat=", fmt.Sprintf("%f", fix.Latitude))
|
||||
print(", long=", fmt.Sprintf("%f", fix.Longitude))
|
||||
print(", altitude:=", fix.Altitude)
|
||||
print(", lat=")
|
||||
print(fix.Latitude)
|
||||
print(", long=")
|
||||
print(fix.Longitude)
|
||||
print(", altitude=", fix.Altitude)
|
||||
print(", satellites=", fix.Satellites)
|
||||
if fix.Speed != 0 {
|
||||
print(", speed=")
|
||||
print(fix.Speed)
|
||||
}
|
||||
if fix.Heading != 0 {
|
||||
print(", heading=")
|
||||
print(fix.Heading)
|
||||
}
|
||||
println()
|
||||
} else {
|
||||
println("No fix")
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package hcsr04
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/hd44780i2c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Note: most HD44780 LCD modules requires 5V power, however some variations
|
||||
// use 3.3V (and may be damaged by 5V).
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
lcd := hd44780i2c.New(machine.I2C0, 0x27) // some modules have address 0x3F
|
||||
|
||||
lcd.Configure(hd44780i2c.Config{
|
||||
Width: 16, // required
|
||||
Height: 2, // required
|
||||
CursorOn: true,
|
||||
CursorBlink: true,
|
||||
})
|
||||
|
||||
lcd.Print([]byte(" TinyGo\n LCD Test "))
|
||||
|
||||
// CGRAM address 0x0-0x7 can be used to store 8 custom characters
|
||||
lcd.CreateCharacter(0x0, []byte{0x00, 0x11, 0x0E, 0x1F, 0x15, 0x1F, 0x1F, 0x1F})
|
||||
lcd.Print([]byte{0x0})
|
||||
|
||||
// You can use https://maxpromer.github.io/LCD-Character-Creator/
|
||||
// to crete your own characters.
|
||||
|
||||
time.Sleep(time.Millisecond * 7000)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
lcd.BacklightOn(false)
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
lcd.BacklightOn(true)
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
lcd.CursorOn(false)
|
||||
lcd.CursorBlink(false)
|
||||
|
||||
i := 0
|
||||
for {
|
||||
|
||||
lcd.ClearDisplay()
|
||||
lcd.SetCursor(2, 1)
|
||||
lcd.Print([]byte(strconv.FormatInt(int64(i), 10)))
|
||||
i++
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/hts221"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := hts221.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("HTS221 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure() // power on and calibrate
|
||||
|
||||
for {
|
||||
|
||||
h, _ := sensor.ReadHumidity()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("h =", float32(h)/100.0, "% / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/adt7410"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := i2csoft.New(machine.SCL_PIN, machine.SDA_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{
|
||||
Frequency: 400e3,
|
||||
})
|
||||
|
||||
sensor := adt7410.New(i2c)
|
||||
sensor.Configure()
|
||||
|
||||
for {
|
||||
temp := sensor.ReadTempF()
|
||||
fmt.Printf("temperature: %f\r\n", temp)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,22 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
black = color.RGBA{0, 0, 0, 255}
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
red = color.RGBA{255, 0, 0, 255}
|
||||
@@ -25,16 +16,15 @@ var (
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
machine.TFT_BACKLIGHT.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display.Configure(ili9341.Config{})
|
||||
width, height := display.Size()
|
||||
|
||||
display.FillScreen(black)
|
||||
machine.TFT_BACKLIGHT.High()
|
||||
|
||||
display.FillRectangle(0, 0, width/2, height/2, white)
|
||||
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
||||
display.FillRectangle(0, height/2, width/2, height/2, green)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 24000000,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.D3
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D0,
|
||||
machine.D1,
|
||||
machine.D2,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
display := ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.TFT_BACKLIGHT
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI3.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.LCD_BACKLIGHT
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
@@ -25,16 +25,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8)]uint16{}
|
||||
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8) * 2]uint8{}
|
||||
|
||||
startTime int64
|
||||
frame int64
|
||||
@@ -53,20 +44,17 @@ var (
|
||||
palette [16]uint16
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
// configure backlight
|
||||
machine.TFT_BACKLIGHT.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
print("width, height == ")
|
||||
width, height := display.Size()
|
||||
println(width, height)
|
||||
|
||||
machine.TFT_BACKLIGHT.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
DrawBackground()
|
||||
|
||||
startTime = time.Now().UnixNano()
|
||||
@@ -188,7 +176,8 @@ func main() {
|
||||
c = BGCOLOR
|
||||
}
|
||||
}
|
||||
frameBuffer[y*int(width)+x] = c
|
||||
frameBuffer[(y*int(width)+x)*2] = byte(c >> 8)
|
||||
frameBuffer[(y*int(width)+x)*2+1] = byte(c)
|
||||
bx1++ // Increment bitmap position counters (X axis)
|
||||
bgx1++
|
||||
}
|
||||
@@ -199,7 +188,7 @@ func main() {
|
||||
bgy++
|
||||
}
|
||||
|
||||
display.DrawRGBBitmap(minx, miny, frameBuffer[:width*height], width, height)
|
||||
display.DrawRGBBitmap8(minx, miny, frameBuffer[:width*height*2], width, height)
|
||||
|
||||
// Show approximate frame rate
|
||||
frame++
|
||||
@@ -224,11 +213,13 @@ func DrawBackground() {
|
||||
b = graphics.Background[j*byteWidth+k/8]
|
||||
}
|
||||
if b&0x80 == 0 {
|
||||
frameBuffer[k] = BGCOLOR
|
||||
frameBuffer[2*k] = byte(BGCOLOR >> 8)
|
||||
frameBuffer[2*k+1] = byte(BGCOLOR & 0xFF)
|
||||
} else {
|
||||
frameBuffer[k] = GRIDCOLOR
|
||||
frameBuffer[2*k] = byte(GRIDCOLOR >> 8)
|
||||
frameBuffer[2*k+1] = byte(GRIDCOLOR & 0xFF)
|
||||
}
|
||||
}
|
||||
display.DrawRGBBitmap(0, j, frameBuffer[0:w], w, 1)
|
||||
display.DrawRGBBitmap8(0, j, frameBuffer[0:w*2], w, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
red = color.RGBA{255, 0, 0, 255}
|
||||
blue = color.RGBA{0, 0, 255, 255}
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
@@ -25,16 +16,15 @@ var (
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display := initdisplay.InitDisplay()
|
||||
|
||||
machine.TFT_BACKLIGHT.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display.Configure(ili9341.Config{})
|
||||
width, height := display.Size()
|
||||
|
||||
display.FillScreen(black)
|
||||
machine.TFT_BACKLIGHT.High()
|
||||
|
||||
display.FillRectangle(0, 0, width/2, height/2, white)
|
||||
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
||||
display.FillRectangle(0, height/2, width/2, height/2, green)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# examples/ili9341/slideshow
|
||||
|
||||

|
||||
|
||||
This example uses the image package for TinyGo to display png and jpeg images.
|
||||
|
||||
## How to create an image
|
||||
|
||||
The following program will output an image binary like the one in [images.go](./images.go).
|
||||
|
||||
```
|
||||
go run ./examples/ili9341/slideshow/convert2bin ./path/to/png_or_jpg.png
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
Displaying a 320x240 png or jpeg often requires more than 50KB of memory.
|
||||
The examples include samd21 settings, but if you run them as is, you will get a memory size error.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
"tinygo.org/x/drivers/image/jpeg"
|
||||
"tinygo.org/x/drivers/image/png"
|
||||
)
|
||||
|
||||
var (
|
||||
black = color.RGBA{0, 0, 0, 255}
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
red = color.RGBA{255, 0, 0, 255}
|
||||
blue = color.RGBA{0, 0, 255, 255}
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := run()
|
||||
for err != nil {
|
||||
errorMessage(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
width, height := display.Size()
|
||||
if width < 320 || height < 240 {
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
}
|
||||
|
||||
display.FillScreen(black)
|
||||
|
||||
for {
|
||||
err := drawJpeg(display)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
err = drawPng(display)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Define the buffer required for the callback. In most cases, this setting
|
||||
// should be sufficient. For jpeg, the callback will always be called every
|
||||
// 3*8*8*4 pix. png will be called every line, i.e. every width pix.
|
||||
var buffer [3 * 8 * 8 * 4]uint16
|
||||
|
||||
func drawPng(display *ili9341.Device) error {
|
||||
p := strings.NewReader(pngImage)
|
||||
png.SetCallback(buffer[:], func(data []uint16, x, y, w, h, width, height int16) {
|
||||
err := display.DrawRGBBitmap(x, y, data[:w*h], w, h)
|
||||
if err != nil {
|
||||
errorMessage(fmt.Errorf("error drawPng: %s", err))
|
||||
}
|
||||
})
|
||||
|
||||
return png.Decode(p)
|
||||
}
|
||||
|
||||
func drawJpeg(display *ili9341.Device) error {
|
||||
p := strings.NewReader(jpegImage)
|
||||
jpeg.SetCallback(buffer[:], func(data []uint16, x, y, w, h, width, height int16) {
|
||||
err := display.DrawRGBBitmap(x, y, data[:w*h], w, h)
|
||||
if err != nil {
|
||||
errorMessage(fmt.Errorf("error drawJpeg: %s", err))
|
||||
}
|
||||
})
|
||||
|
||||
return jpeg.Decode(p)
|
||||
}
|
||||
|
||||
func errorMessage(err error) {
|
||||
for {
|
||||
fmt.Printf("%s\r\n", err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/ina260"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
dev := ina260.New(machine.I2C0)
|
||||
dev.Configure(ina260.Config{
|
||||
AverageMode: ina260.AVGMODE_16,
|
||||
VoltConvTime: ina260.CONVTIME_140USEC,
|
||||
CurrentConvTime: ina260.CONVTIME_140USEC,
|
||||
Mode: ina260.MODE_CONTINUOUS | ina260.MODE_VOLTAGE | ina260.MODE_CURRENT,
|
||||
})
|
||||
|
||||
if dev.Connected() {
|
||||
println("INA260 detected")
|
||||
} else {
|
||||
println("INA260 NOT detected")
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
microvolts := dev.Voltage()
|
||||
microamps := dev.Current()
|
||||
microwatts := dev.Power()
|
||||
|
||||
println(fmtD(microvolts, 4, 3), "mV,", fmtD(microamps, 4, 3), "mA,", fmtD(microwatts, 4, 3), "mW")
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func fmtD(val int32, i int, f int) string {
|
||||
result := make([]byte, i+f+1)
|
||||
neg := false
|
||||
|
||||
if val < 0 {
|
||||
val = -val
|
||||
neg = true
|
||||
}
|
||||
|
||||
for p := len(result) - 1; p >= 0; p-- {
|
||||
result[p] = byte(int32('0') + (val % 10))
|
||||
val = val / 10
|
||||
|
||||
if p == i+1 && p > 0 {
|
||||
p--
|
||||
result[p] = '.'
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
result[0] = '-'
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/keypad4x4"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mapping := map[uint8]string{
|
||||
1: "1",
|
||||
2: "2",
|
||||
3: "3",
|
||||
4: "A",
|
||||
5: "4",
|
||||
6: "5",
|
||||
7: "6",
|
||||
8: "B",
|
||||
9: "7",
|
||||
10: "8",
|
||||
11: "9",
|
||||
12: "C",
|
||||
13: "*",
|
||||
14: "0",
|
||||
15: "#",
|
||||
16: "D",
|
||||
}
|
||||
|
||||
keypadDevice := keypad4x4.NewDevice(machine.D2, machine.D3, machine.D4, machine.D5, machine.D6, machine.D7, machine.D8, machine.D9)
|
||||
keypadDevice.Configure()
|
||||
|
||||
for {
|
||||
key := keypadDevice.GetKey()
|
||||
if key != keypad4x4.NoKeyPressed {
|
||||
println("Button: ", mapping[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,31 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
maxSpeed = 30000
|
||||
maxSpeed = 100
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.InitPWM()
|
||||
err := machine.TCC0.Configure(machine.PWMConfig{
|
||||
Period: 16384e3, // 16.384ms
|
||||
})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, machine.PWM{machine.D12})
|
||||
spc, err := machine.TCC0.Channel(machine.D12)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, spc, machine.TCC0)
|
||||
wheel.Configure()
|
||||
|
||||
for i := 0; i <= 10; i++ {
|
||||
println("Forward")
|
||||
var i uint16
|
||||
for i = 0; i < maxSpeed; i += 1000 {
|
||||
var i uint32
|
||||
for i = 0; i < maxSpeed; i += 10 {
|
||||
wheel.Forward(i)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
@@ -30,7 +42,7 @@ func main() {
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
|
||||
println("Backward")
|
||||
for i = 0; i < maxSpeed; i += 1000 {
|
||||
for i = 0; i < maxSpeed; i += 10 {
|
||||
wheel.Backward(i)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
@@ -8,19 +8,38 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
maxSpeed = 30000
|
||||
maxSpeed = 100
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.InitPWM()
|
||||
machine.D11.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.D12.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
wheel := l9110x.NewWithSpeed(machine.PWM{machine.D11}, machine.PWM{machine.D12})
|
||||
err := machine.TCC0.Configure(machine.PWMConfig{})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ca, err := machine.TCC0.Channel(machine.D11)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cb, err := machine.TCC0.Channel(machine.D12)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
wheel := l9110x.NewWithSpeed(ca, cb, machine.TCC0)
|
||||
wheel.Configure()
|
||||
|
||||
for i := 0; i <= 10; i++ {
|
||||
println("Forward")
|
||||
var i uint16
|
||||
for i = 0; i < maxSpeed; i += 1000 {
|
||||
var i uint32
|
||||
for i = 0; i < maxSpeed; i += 10 {
|
||||
wheel.Forward(i)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
@@ -30,7 +49,7 @@ func main() {
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
|
||||
println("Backward")
|
||||
for i = 0; i < maxSpeed; i += 1000 {
|
||||
for i = 0; i < maxSpeed; i += 10 {
|
||||
wheel.Backward(i)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lis2mdl"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
compass := lis2mdl.New(machine.I2C0)
|
||||
|
||||
if !compass.Connected() {
|
||||
for {
|
||||
println("LIS2MDL not connected!")
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
compass.Configure(lis2mdl.Configuration{}) //default settings
|
||||
|
||||
for {
|
||||
heading := compass.ReadCompass()
|
||||
println("Heading:", heading)
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lps22hb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := lps22hb.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("LPS22HB not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure()
|
||||
|
||||
for {
|
||||
|
||||
p, _ := sensor.ReadPressure()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("p =", float32(p)/1000.0, "hPa / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
// note: the device would power down itself after each query
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
"tinygo.org/x/drivers/lsm303agr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
accel_mag := lsm303agr.New(machine.I2C0)
|
||||
|
||||
if !accel_mag.Connected() {
|
||||
println("LSM303AGR/MAG not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
accel_mag.Configure(lsm303agr.Configuration{}) //default settings
|
||||
|
||||
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()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Connects to an LSM6DSOX I2C a 6 axis Inertial Measurement Unit (IMU)
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm6dsox"
|
||||
)
|
||||
|
||||
const (
|
||||
PLOTTER = true
|
||||
SHOW_ACCELERATION = false
|
||||
SHOW_ROTATION = true
|
||||
SHOW_TEMPERATURE = false
|
||||
|
||||
// calibration is naive, good enough for a demo: do not shake a second after flashing
|
||||
GYRO_CALIBRATION = true
|
||||
)
|
||||
|
||||
var cal = [...]float32{0, 0, 0}
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
device := lsm6dsox.New(machine.I2C0)
|
||||
device.Configure(lsm6dsox.Configuration{
|
||||
AccelRange: lsm6dsox.ACCEL_2G,
|
||||
AccelSampleRate: lsm6dsox.ACCEL_SR_104,
|
||||
GyroRange: lsm6dsox.GYRO_250DPS,
|
||||
GyroSampleRate: lsm6dsox.GYRO_SR_104,
|
||||
})
|
||||
|
||||
for {
|
||||
|
||||
if !device.Connected() {
|
||||
println("LSM6DSOX not connected")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// heuristic: after successful calibration the value can't be 0
|
||||
if GYRO_CALIBRATION && cal[0] == 0 {
|
||||
calibrateGyro(device)
|
||||
}
|
||||
|
||||
ax, ay, az := device.ReadAcceleration()
|
||||
gx, gy, gz := device.ReadRotation()
|
||||
t, _ := device.ReadTemperature()
|
||||
|
||||
if PLOTTER {
|
||||
printPlotter(ax, ay, az, gx, gy, gz, t)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
} else {
|
||||
printMonitor(ax, ay, az, gx, gy, gz, t)
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func calibrateGyro(device *lsm6dsox.Device) {
|
||||
for i := 0; i < 100; i++ {
|
||||
gx, gy, gz := device.ReadRotation()
|
||||
cal[0] += float32(gx) / 1000000
|
||||
cal[1] += float32(gy) / 1000000
|
||||
cal[2] += float32(gz) / 1000000
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
cal[0] /= 100
|
||||
cal[1] /= 100
|
||||
cal[2] /= 100
|
||||
}
|
||||
|
||||
// Arduino IDE's Serial Plotter
|
||||
func printPlotter(ax, ay, az, gx, gy, gz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("AX:%f, AY:%f, AZ:%f,", axis(ax, 0), axis(ay, 0), axis(az, 0))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("GX:%f, GY:%f, GZ:%f,", axis(gx, cal[0]), axis(gy, cal[1]), axis(gz, cal[2]))
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("T:%f", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
// Any Serial Monitor
|
||||
func printMonitor(ax, ay, az, gx, gy, gz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("Acceleration: %f, %f, %f\r\n", axis(ax, 0), axis(ay, 0), axis(az, 0))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("Rotation: %f, %f, %f\r\n", axis(gx, cal[0]), axis(gy, cal[1]), axis(gz, cal[2]))
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("Temperature C: %f\r\n", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
func axis(raw int32, cal float32) float32 {
|
||||
return float32(raw)/1000000 - cal
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// LSM9DS1, 9 axis Inertial Measurement Unit (IMU)
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm9ds1"
|
||||
)
|
||||
|
||||
const (
|
||||
PLOTTER = false
|
||||
SHOW_ACCELERATION = true
|
||||
SHOW_ROTATION = true
|
||||
SHOW_MAGNETIC_FIELD = true
|
||||
SHOW_TEMPERATURE = true
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// I2C configure
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
// LSM9DS1 setup
|
||||
device := lsm9ds1.New(machine.I2C0)
|
||||
err := device.Configure(lsm9ds1.Configuration{
|
||||
AccelRange: lsm9ds1.ACCEL_2G,
|
||||
AccelSampleRate: lsm9ds1.ACCEL_SR_119,
|
||||
GyroRange: lsm9ds1.GYRO_250DPS,
|
||||
GyroSampleRate: lsm9ds1.GYRO_SR_119,
|
||||
MagRange: lsm9ds1.MAG_4G,
|
||||
MagSampleRate: lsm9ds1.MAG_SR_40,
|
||||
})
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
if con, err := device.Connected(); !con || err != nil {
|
||||
println("LSM9DS1 not connected")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
ax, ay, az, _ := device.ReadAcceleration()
|
||||
gx, gy, gz, _ := device.ReadRotation()
|
||||
mx, my, mz, _ := device.ReadMagneticField()
|
||||
t, _ := device.ReadTemperature()
|
||||
|
||||
if PLOTTER {
|
||||
printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
} else {
|
||||
printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t)
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Arduino IDE's Serial Plotter
|
||||
func printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("AX:%f, AY:%f, AZ:%f,", axis(ax), axis(ay), axis(az))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("GX:%f, GY:%f, GZ:%f,", axis(gx), axis(gy), axis(gz))
|
||||
}
|
||||
if SHOW_MAGNETIC_FIELD {
|
||||
fmt.Printf("MX:%d, MY:%d, MZ:%d,", mx, my, mz)
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("T:%f", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
// Any Serial Monitor
|
||||
func printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("Acceleration (g): %f, %f, %f\r\n", axis(ax), axis(ay), axis(az))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("Rotation (dps): %f, %f, %f\r\n", axis(gx), axis(gy), axis(gz))
|
||||
}
|
||||
if SHOW_MAGNETIC_FIELD {
|
||||
fmt.Printf("Magnetic field (nT): %d, %d, %d\r\n", mx, my, mz)
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("Temperature C: %f\r\n", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
func axis(raw int32) float32 {
|
||||
return float32(raw) / 1000000
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/max72xx"
|
||||
)
|
||||
|
||||
// example for a 4 digit 7 segment display
|
||||
func main() {
|
||||
// Pins for Arduino Nano 33 IOT
|
||||
err := machine.SPI0.Configure(machine.SPIConfig{
|
||||
SDO: machine.D11, // default SDO pin
|
||||
SCK: machine.D13, // default sck pin
|
||||
LSBFirst: false,
|
||||
Frequency: 10000000,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
|
||||
driver := max72xx.NewDevice(machine.SPI0, machine.D6)
|
||||
driver.Configure()
|
||||
|
||||
digitNumber := 4
|
||||
|
||||
driver.StopDisplayTest()
|
||||
driver.SetDecodeMode(4)
|
||||
driver.SetScanLimit(4)
|
||||
driver.StopShutdownMode()
|
||||
|
||||
for i := 1; i < int(digitNumber); i++ {
|
||||
driver.WriteCommand(byte(i), byte(Blank))
|
||||
}
|
||||
|
||||
for {
|
||||
for _, character := range characters {
|
||||
println("writing", "characterValue:", character.String())
|
||||
driver.WriteCommand(byte(4), byte(character))
|
||||
driver.WriteCommand(byte(3), byte(character))
|
||||
driver.WriteCommand(byte(2), byte(character))
|
||||
driver.WriteCommand(byte(1), byte(character))
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var characters = []Character{
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five,
|
||||
Six,
|
||||
Seven,
|
||||
Eight,
|
||||
Nine,
|
||||
Dash,
|
||||
E,
|
||||
H,
|
||||
L,
|
||||
P,
|
||||
Blank,
|
||||
Dot,
|
||||
}
|
||||
|
||||
// Each bit translates to a pin, which is driven high or low
|
||||
type Character byte
|
||||
|
||||
func (char Character) String() string {
|
||||
switch char {
|
||||
case Zero:
|
||||
return "0"
|
||||
case One:
|
||||
return "1"
|
||||
case Two:
|
||||
return "2"
|
||||
case Three:
|
||||
return "3"
|
||||
case Four:
|
||||
return "4"
|
||||
case Five:
|
||||
return "5"
|
||||
case Six:
|
||||
return "6"
|
||||
case Seven:
|
||||
return "7"
|
||||
case Eight:
|
||||
return "8"
|
||||
case Nine:
|
||||
return "9"
|
||||
case Dash:
|
||||
return "-"
|
||||
case E:
|
||||
return "E"
|
||||
case H:
|
||||
return "H"
|
||||
case L:
|
||||
return "L"
|
||||
case P:
|
||||
return "P"
|
||||
case Blank:
|
||||
return ""
|
||||
case Dot:
|
||||
return "."
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
const (
|
||||
Zero Character = 0 //126
|
||||
One Character = 1 //48
|
||||
Two Character = 2 // 109
|
||||
Three Character = 3 // 121
|
||||
Four Character = 4
|
||||
Five Character = 5
|
||||
Six Character = 6
|
||||
Seven Character = 7
|
||||
Eight Character = 8
|
||||
Nine Character = 9
|
||||
Dash Character = 10
|
||||
E Character = 11
|
||||
H Character = 12
|
||||
L Character = 13
|
||||
P Character = 14
|
||||
Blank Character = 15
|
||||
Dot Character = 128
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
// This example demonstrates putting several mcp23017 devices together into
|
||||
// a single virtual I/O array.
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/mcp23017"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := machine.I2C0.Configure(machine.I2CConfig{
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Assume the devices are at addresses 0x20, 0x21
|
||||
dev, err := mcp23017.NewI2CDevices(machine.I2C0, 0x20, 0x21)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Configure pin 0 for input and all the others for output.
|
||||
if err := dev.SetModes([]mcp23017.PinMode{
|
||||
mcp23017.Input | mcp23017.Pullup,
|
||||
mcp23017.Output,
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
input := dev.Pin(0)
|
||||
// Make a mask that represents all the output pins.
|
||||
// Note that this leverages the driver behaviour which replicates the highest bit in
|
||||
// the last slice element (1 in this case) to all other pins
|
||||
outputMask := mcp23017.PinSlice{^mcp23017.Pins(1 << 0)} // All except pin 0
|
||||
inputVal, err := input.Get()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println("input value: ", inputVal)
|
||||
// Set the values of all the output pins.
|
||||
err = dev.SetPins(mcp23017.PinSlice{0b1011011_01101110, 0b11111101_11100110}, outputMask)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/mcp23017"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := machine.I2C0.Configure(machine.I2CConfig{
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dev, err := mcp23017.NewI2C(machine.I2C0, 0x20)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Configure pin 0 for input and all the others for output.
|
||||
if err := dev.SetModes([]mcp23017.PinMode{
|
||||
mcp23017.Input | mcp23017.Pullup,
|
||||
mcp23017.Output,
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
input := dev.Pin(0)
|
||||
outputMask := ^mcp23017.Pins(1 << 0) // All except pin 0
|
||||
inputVal, err := input.Get()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println("input value: ", inputVal)
|
||||
// Set the values of all the output pins.
|
||||
err = dev.SetPins(0b1011011_01101110, outputMask)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/mcp2515"
|
||||
)
|
||||
|
||||
var (
|
||||
spi = machine.SPI0
|
||||
csPin = machine.D5
|
||||
)
|
||||
|
||||
func main() {
|
||||
spi.Configure(machine.SPIConfig{
|
||||
Frequency: 115200,
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Mode: 0})
|
||||
can := mcp2515.New(spi, csPin)
|
||||
can.Configure()
|
||||
err := can.Begin(mcp2515.CAN500kBps, mcp2515.Clock8MHz)
|
||||
if err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
for {
|
||||
err := can.Tx(0x111, 8, []byte{0x00, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA})
|
||||
if err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
if can.Received() {
|
||||
msg, err := can.Rx()
|
||||
if err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
fmt.Printf("CAN-ID: %03X dlc: %d data: ", msg.ID, msg.Dlc)
|
||||
for _, b := range msg.Data {
|
||||
fmt.Printf("%02X ", b)
|
||||
}
|
||||
fmt.Print("\r\n")
|
||||
}
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
|
||||
func failMessage(msg string) {
|
||||
for {
|
||||
println(msg)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/p1am"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for {
|
||||
if err := loop(); err != nil {
|
||||
fmt.Printf("loop failed, retrying: %v\n", err)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
func loop() error {
|
||||
led := machine.LED
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
sw := machine.SWITCH
|
||||
sw.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
|
||||
if err := p1am.Controller.Initialize(); err != nil {
|
||||
return fmt.Errorf("initializing controller: %w", err)
|
||||
}
|
||||
|
||||
version, err := p1am.Controller.Version()
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching base controller version: %w", err)
|
||||
}
|
||||
fmt.Printf("Base controller version: %d.%d.%d\n", version[0], version[1], version[2])
|
||||
|
||||
for i := 1; i <= p1am.Controller.Slots; i++ {
|
||||
slot := p1am.Controller.Slot(i)
|
||||
fmt.Printf("Slot %d: ID 0x%08x, Props %+v\n", i, slot.ID, slot.Props)
|
||||
}
|
||||
|
||||
slot1 := p1am.Controller.Slot(1)
|
||||
var lastInput uint32
|
||||
state := sw.Get()
|
||||
for {
|
||||
if active, err := p1am.Controller.Active(); err != nil || !active {
|
||||
return fmt.Errorf("controller active %v: %v", active, err)
|
||||
}
|
||||
if state != sw.Get() {
|
||||
state = sw.Get()
|
||||
fmt.Printf("New switch state: %v\n", state)
|
||||
if slot1.Props.DO > 0 {
|
||||
if err := slot1.Channel(1).WriteDiscrete(state); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if slot1.Props.DI > 0 {
|
||||
sstate, err := slot1.ReadDiscrete()
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading slot: %w", err)
|
||||
}
|
||||
if sstate != lastInput {
|
||||
lastInput = sstate
|
||||
fmt.Printf("new DI state: %#b\n", sstate)
|
||||
}
|
||||
}
|
||||
if state {
|
||||
led.High()
|
||||
} else {
|
||||
led.Low()
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 50, 0, time.UTC))
|
||||
|
||||
rtc.SetAlarm(time.Date(2006, 1, 2, 15, 5, 0, 0, time.UTC))
|
||||
rtc.EnableAlarmInterrupt()
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
|
||||
if rtc.AlarmTriggered() {
|
||||
fmt.Printf("alarm triggered\r\n")
|
||||
rtc.ClearAlarm()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
for {
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1HZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32HZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1KHZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32KHZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_DISABLE)
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
|
||||
|
||||
rtc.SetTimer(15 * time.Second)
|
||||
rtc.EnableTimerInterrupt()
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
|
||||
if rtc.TimerTriggered() {
|
||||
fmt.Printf("timer triggered\r\n")
|
||||
rtc.ClearTimer()
|
||||
rtc.SetTimer(10 * time.Second)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// This is a sensor station that uses a RTL8720DN running on the device UART2.
|
||||
// It creates an MQTT connection that publishes a message every second
|
||||
// to an MQTT broker.
|
||||
//
|
||||
// In other words:
|
||||
// Your computer <--> USB-CDC <--> MCU <--> UART2 <--> RTL8720DN <--> Internet <--> MQTT broker.
|
||||
//
|
||||
// You must install the Paho MQTT package to build this program:
|
||||
//
|
||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||
//
|
||||
// You can check that mqttpub is running successfully with the following command.
|
||||
//
|
||||
// mosquitto_sub -h test.mosquitto.org -t tinygo
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/net/mqtt"
|
||||
"tinygo.org/x/drivers/rtl8720dn"
|
||||
)
|
||||
|
||||
// You can override the setting with the init() in another source code.
|
||||
// func init() {
|
||||
// ssid = "your-ssid"
|
||||
// password = "your-password"
|
||||
// debug = true
|
||||
// server = "tinygo.org"
|
||||
// }
|
||||
|
||||
var (
|
||||
ssid string
|
||||
password string
|
||||
server string = "tcp://test.mosquitto.org:1883"
|
||||
debug = false
|
||||
)
|
||||
|
||||
var buf [0x400]byte
|
||||
|
||||
var lastRequestTime time.Time
|
||||
var conn net.Conn
|
||||
var adaptor *rtl8720dn.RTL8720DN
|
||||
|
||||
func main() {
|
||||
err := run()
|
||||
for err != nil {
|
||||
fmt.Printf("error: %s\r\n", err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
topic = "tinygo"
|
||||
)
|
||||
|
||||
func run() error {
|
||||
rtl, err := setupRTL8720DN()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip, subnet, gateway, err := rtl.GetIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("IP Address : %s\r\n", ip)
|
||||
fmt.Printf("Mask : %s\r\n", subnet)
|
||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.AddBroker(server).SetClientID("tinygo-client-" + randomString(10))
|
||||
|
||||
println("Connectng to MQTT...")
|
||||
cl := mqtt.NewClient(opts)
|
||||
if token := cl.Connect(); token.Wait() && token.Error() != nil {
|
||||
failMessage(token.Error().Error())
|
||||
}
|
||||
|
||||
for i := 0; ; i++ {
|
||||
println("Publishing MQTT message...")
|
||||
data := []byte(fmt.Sprintf(`{"e":[{"n":"hello %d","v":101}]}`, i))
|
||||
token := cl.Publish(topic, 0, false, data)
|
||||
token.Wait()
|
||||
if err := token.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Right now this code is never reached. Need a way to trigger it...
|
||||
println("Disconnecting MQTT...")
|
||||
cl.Disconnect(100)
|
||||
|
||||
println("Done.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns an int >= min, < max
|
||||
func randomInt(min, max int) int {
|
||||
return min + rand.Intn(max-min)
|
||||
}
|
||||
|
||||
// Generate a random string of A-Z chars with len = l
|
||||
func randomString(len int) string {
|
||||
bytes := make([]byte, len)
|
||||
for i := 0; i < len; i++ {
|
||||
bytes[i] = byte(randomInt(65, 90))
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func failMessage(msg string) {
|
||||
for {
|
||||
println(msg)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"device/sam"
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/rtl8720dn"
|
||||
)
|
||||
|
||||
var (
|
||||
uart UARTx
|
||||
)
|
||||
|
||||
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)
|
||||
if debug {
|
||||
waitSerial()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Wait for user to open serial console
|
||||
func waitSerial() {
|
||||
for !machine.Serial.DTR() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user