Compare commits

...

381 Commits

Author SHA1 Message Date
deadprogram 5130e9a120 sx126x: update to use new device package location
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-02-19 11:45:03 +01:00
deadprogram ee70298bc4 modules: add tinygo.org/x/device package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-02-19 11:44:17 +01:00
Yurii Soldak 45dce188f5 lsmXXX: unified, error handling, memory management 2022-02-18 06:10:27 +01:00
Steven Pearson b3c0315a09 Driver for SSD1289 LCD 2022-02-18 06:01:55 +01:00
BCG 0ced12683c Revert "Added support for 125MHz to WS2812 for RP2040"
This reverts commit b4eb406a43 (erroneous
push).
2022-02-14 01:06:23 -05:00
BCG b4eb406a43 Added support for 125MHz to WS2812 for RP2040 2022-02-14 00:48:33 -05:00
sago35 10bd48c39d ws2812: add support for m5stamp-c3 2022-02-11 23:47:55 +01:00
Yurii Soldak ad3ef92cfe lps22hb: pin rename, sync with main repo 2022-01-29 23:02:42 +01:00
deadprogram f7dce6ae22 wifinina: correct sendParamStr to handle empty strings, such as when connecting to an unsecured access point.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-26 23:05:50 +01:00
deadprogram a15f2167cc release: prepare for v0.19.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-26 18:26:16 +01:00
deadprogram 5d5378a47c all: update license year to 2022
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-26 18:25:15 +01:00
deadprogram 3ceb688663 examples/wifi: add unified example for tcpclient that compiles for all supported wifi adaptors
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-24 13:24:39 +01:00
deadprogram 941c1c9057 wifi/espat, rtl8720dn, wifinina, net: modify to use Adapter interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-24 13:24:39 +01:00
deadprogram d8c813d515 wifi/espat, rtl8720dn, wifinina: move towards standard common interface for wifi adaptors
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-24 13:24:39 +01:00
Drayton Munster 905fc6fce3 hd44780: fix 4-bit data length flag 2022-01-20 20:01:37 +01:00
Drayton Munster 80913d5fe7 Reset data pins to output mode after reading 2022-01-20 20:01:37 +01:00
Olivier Fauchon b6c750ccd1 sx126x: Driver for Semtech sx126x radio modules and optional RF Switch.
This first version of the driver has been tested with STM32WL SoC,
	which embeddeds SX1262 radio on the same die.
2022-01-15 17:22:36 +01:00
deadprogram 43899e1330 build: remove smoketest for Arduino keyboard4x4 for now
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-12 18:26:10 +01:00
sago35 45c68ef0fc ft6336: add support for ft6336 2022-01-04 15:54:35 +01:00
Olivier Fauchon 025a66655f shtc3: Sensirion SHTC3 Relative Humidity / Temperature i2c sensor 2021-12-28 16:02:10 +01:00
deadprogram 121e8147f7 hd44780i2c: clean up for go fmt
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-24 16:00:39 +01:00
Alan Wang b48bc5ac5d Update hd44780i2c.go 2021-12-24 11:54:00 +01:00
Alan Wang 0d40c99d1f Add files via upload 2021-12-22 16:49:54 +01:00
Alan Wang bee7422c3a Fix Nano 33 BLE drivers (#351)
Fix HTS221, LPS22HB and APDS9960 drivers and their examples for Arduino Nano 33 BLE:

* Update hts221_nano_33_ble.go
* Update lps22hb_nano_33_ble.go
* Update apds9960_nano_33_ble.go
2021-12-20 09:57:37 +01:00
spearson78 43099c5d5f XPT2046 Touch driver (#350)
Co-authored-by: Steven Pearson <steven.pearson.78@gmail.com>
2021-12-14 09:14:10 +09:00
Yurii Soldak 0f9b9d873b wifinina: avoid busy wait 2021-12-10 12:15:56 +01:00
sago35 114e24870e ili9341, ili9342: add support for m5stack 2021-11-27 13:03:07 +01:00
soypat b33c84ff78 add PCA9685 driver 2021-11-21 14:46:15 +01:00
sago35 966210f1b0 ili9341, ili9342: add support for m5stack-core2 2021-11-20 12:20:34 +01:00
deadprogram 90a13a697b release: prepare for v0.18.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-18 15:25:24 +01:00
deadprogram d632eb888f docs: add LSM9DS1 to list
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-18 11:39:27 +01:00
Yurii Soldak f6761a9079 lsm9ds1: minimal implementation 2021-11-18 11:36:16 +01:00
sago35 51c3aa271b axp192: add support for AXP192 single Cell Li-Battery and power system management IC 2021-11-18 11:18:30 +01:00
soypat 520234e9f8 mcp3008: fix bitshift bug 2021-11-14 18:10:48 +01:00
Yurii Soldak 334ed57373 wifinina: control nina pins, for example leds 2021-11-12 15:32:21 +01:00
Sam Lader 3637033fec Fix broken link for SHT3x datasheet (#327)
docs: fix broken link for SHT3x datasheet
2021-11-06 21:26:08 +01:00
deadprogram 233866443c docs: update list of supported drivers with recent additions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-06 18:34:08 +01:00
Alan Wang 65fd7aa1a1 Add support for APDS-9960, Digital Proximity, Ambient Light, RGB and Gesture Sensor (#308)
apds9960: add support for apds9960
2021-11-06 11:22:39 +01:00
Alan Wang 82e9e4a7f3 Add support for LPS22HB MEMS nano pressure sensor (#297)
lps22hb: add support for lps22hb
2021-11-06 11:14:21 +01:00
deadprogram 76ff632134 hts221: update build tags for Go 1.17+
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-06 11:05:25 +01:00
Alan Wang cd2694e85f Add support for HTS221 capacitive digital sensor for relative humidity and temperature (#295)
hts221: Add support for hts221.go
2021-11-06 11:02:30 +01:00
sago35 734adb6df8 i2csoft: fix Configure() 2021-11-04 15:02:21 +01:00
sago35 2492fcb322 i2csoft: gofmt 2021-11-04 15:02:21 +01:00
sago35 4f82c231cb i2csoft: add source code for each target 2021-11-04 15:02:21 +01:00
sago35 2c9a05a413 i2csoft: remove the return value 2021-11-04 15:02:21 +01:00
sago35 a89a26112e i2csoft: fix baudrate handling 2021-11-04 15:02:21 +01:00
sago35 bd42656644 i2csoft: add support for software I2C 2021-11-04 15:02:21 +01:00
Ayke van Laethem 94729a4f7d ws2812: add support for RISC-V
This commit adds support for two new chips using the RISC-V
architecture: the FE310 (used in the HiFive 1) and the ESP32-C3 from
Espressif.
2021-11-03 19:14:32 +01:00
Ayke van Laethem 050cf4dbbc ws2812: make assembly generator architecture independent 2021-11-03 19:14:32 +01:00
sago35 49c8810432 ili9341: refactor examples/ili9341 2021-10-31 20:12:50 +01:00
Yurii Soldak 4b38841f71 net: fix raddr of tcp conn 2021-10-26 11:22:45 +02:00
Yurii Soldak 3fe3fc64e4 wifinina: fix warnings 2021-09-19 13:05:38 +02:00
Yurii Soldak 0565a15b17 net: fix raddr typo 2021-09-19 13:05:38 +02:00
deadprogram fad9d12e0b examples/ili9341: correct go format
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-18 15:06:56 +02:00
sago35 f2e5278965 image: add support for image/jpeg and image/png (#303)
* Copy from go1.17 image package
* Remove unnecessary files
* Reduce memory usage
* Add examples/ili9341/slideshow
* image: add ./image/README.md
* image: change convert2bin to . /cmd
* Makefile: add ./cmd to NOTEST
2021-09-18 12:18:02 +02:00
Ayke van Laethem 259593e608 ws2812: add support for 168MHz (e.g. Adafruit Feather STM32F405) 2021-09-17 10:19:21 +02:00
Ayke van Laethem 7a2b1b8c90 ws2812: improve timings to be compatible with the WS2811
The WS2811 has a slightly slower data rate, but it is close enough that
a single library can support both LEDs at the same time. In my testing,
this package was already compatible with WS2811 LEDs before this change
when running at 4-5V, but when the voltage dropped to 3V or so the LEDs
started misbehaving. With these improved timings, the LEDs remained of
the correct color even at very low voltages (although blue was starting
to fade due to lack of voltage - that's not a software/protocol issue).
2021-09-17 10:08:46 +02:00
Ayke van Laethem cad03a7d4e ws2812: fix generated build tags 2021-09-17 09:42:28 +02:00
deadprogram 98f5396625 examples/sdcard: correct invalid build tag noticed by @aykevl
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-16 18:31:33 +02:00
deadprogram 3b16972ed8 all: use build directives for both Go1.17 and earlier versions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-16 18:31:33 +02:00
deadprogram b35496dd1b make: correct fmt-check to look in all subdirectories
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-16 18:31:33 +02:00
Yurii Soldak ad6be40966 lsm6dox: minimal correct implementation 2021-09-14 12:10:59 +02:00
Ayke van Laethem b3af3f594e ws2812: generate assembly instead of handwriting it
Previously, a new implementation had to be written for each processor
speed. This is tedious and error-prone, therefore I've rewritten all of
the assembly code using a tool that will calculate exactly how many NOP
instructions are required.

I've also switched from build tags to a switch statement over all
processor speeds.

All in all, this means that:
  - Chips with a supported CPU performance will automatically be
    supported (no build tags necessary).
  - Adding a new chip is as easy as adding the MHz count to the
    generator script and to the switch statement.

Right now this is only for the Cortex-M, but it's certainly feasible to
extend this to other architectures such as the AVR.
2021-09-07 18:00:55 +02:00
sago35 9a3bfd4826 wifinina: add comments 2021-09-06 11:06:59 +02:00
sago35 1ba9ba3143 wifinina: add examples/wifinina/http-get 2021-09-06 11:06:59 +02:00
Yurii Soldak feb1c63656 Instructions on how to flash nina-fw on nano rp2040 connect w/o Arduino IDE 2021-09-05 11:57:07 +02:00
Yurii Soldak 0691ed5205 wifinina: nina-fw update docs 2021-09-05 11:57:07 +02:00
deadprogram e70beede1c ws2812: update examples to use go:build tags required by go 1.17
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-03 11:11:40 +02:00
sago35 92673d996d dht: improve build tag in lowfreq.go 2021-09-02 11:28:22 +02:00
sago35 374e2dfe1d ili9341: change to use drivers.SPI interface 2021-09-01 19:41:27 +02:00
sago35 b35aab6d61 Add support for case-insensitive header names 2021-08-24 10:45:28 +02:00
sago35 358501fc47 Add support for req.URL.RawQuery 2021-08-24 10:45:28 +02:00
sago35 a0119ffc6f rtl8720dn: add examples/rtl8720dn/tcpclient 2021-08-09 21:11:47 +02:00
sago35 58106b5942 Add examples/rtl8720dn/udpstation 2021-08-05 22:18:24 +02:00
sago35 2537c69b0f rtl8720dn: add support for http.Get(), http.Post() and cookie 2021-08-05 08:10:52 +02:00
sago35 633f19c4ac rtl8720dn: add examples/rtl8720dn/mqtt* 2021-07-31 11:02:45 +02:00
sago35 6a4cd9d8e7 rtl8720dn: add examples/rtl8720dn/webserver 2021-07-24 09:44:17 +02:00
sago35 8a4a0ff017 rtl8720dn: add info when debug mode is enabled 2021-07-24 09:28:46 +02:00
deadprogram 1cbf1a6f3d release: v0.17.1
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:38:55 +02:00
deadprogram 001bdb43ba release: v0.17.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:20:03 +02:00
deadprogram f7ae6fac6d modules: switch to use tinygo-org version of tinyfs package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:00:52 +02:00
sago35 a575b2a4ed Update comments 2021-06-27 16:33:32 +02:00
sago35 0bc3702dd0 rtl8720dn: add support for rtl8720dn 2021-06-27 16:33:32 +02:00
sago35 b53a8a17e7 ili9341: add standard SPI driver 2021-06-27 08:08:27 +02:00
sago35 5e117c162c ws2812: rename the pin to ws2812 2021-06-26 14:04:13 +02:00
sago35 24dfd8795a sdcard: add write functionality to examples/sdcard/tinyfs 2021-06-23 18:34:26 +02:00
sago35 a748451cab Merge pull request #275 from tinygo-org/ws2812-add-nrf52833
ws2812: add tag for nrf52833
2021-06-23 20:33:53 +09:00
deadprogram a811483fd4 ws2812: add tag for nrf52833
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-20 11:11:08 +02:00
Daniel Bridges 7b565e8cb0 Disable interrupts before sending ws2812 data 2021-06-17 09:24:49 +02:00
sago35 5645eb3f91 ws2812: add support for qtpy and atsame5x 2021-06-01 21:09:08 +02:00
sago35 6b914f7af7 sdcard: add support for fatfs 2021-05-31 17:26:21 +02:00
Ayke van Laethem 5a02fe068b apa102: use 4-byte buffer to improve speed
Instead of sending the APA102 data byte by byte, it's more efficient to
send multiple bytes at once (especially when the SPI peripheral uses
DMA). This requires the apa102.Device object to be a pointer receiver to
avoid excessive heap allocations.

This commit also just happens to work around a hardware bug on the
nrf52832:
https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52832_Rev2%2FERR%2FnRF52832%2FRev2%2Flatest%2Fanomaly_832_58.html&anchor=anomaly_832_58
2021-05-30 22:39:50 +02:00
Ayke van Laethem 5ecefde991 bmi160: avoid heap allocations
The nrf52 series chips use DMA for writing and reading SPI data, which
means that the transmit and receive buffer slices escape. This can
easily be solved by pre-allocating the buffer in the BMI160 driver and
reusing this buffer every time.
2021-05-30 22:11:27 +02:00
Yurii Soldak 9adbde99a2 wifinina: avoid fmt package 2021-05-28 18:09:29 +02:00
Yurii Soldak a09ec31e7a Fix RSSI command for WiFiNINA
+ Print current SSID
+ Wait for correct time before printing it out
+ Cleanup
2021-05-27 08:00:13 +02:00
sago35 d07ad40373 sdcard: add support for spi sdcard driver 2021-05-23 11:22:42 +02:00
sago35 aa17ffd1cb uart: use machine.Serial as the default output 2021-05-14 13:26:59 +02:00
deadprogram ce03bebc34 release: prepare for release v0.16.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 15:51:16 +02:00
deadprogram dfd652ca1f docs: up to 65 devices
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 15:30:41 +02:00
Ayke van Laethem c765ef3970 servo: add driver using PWM
This PR adds support for controlling servos. For example, on the Arduino
Uno it should be able to control up to 6 servos jitter-free when using
all available PWM pins.

I haven't added support for setting a position in degrees, mainly
because this varies by servo and it's probably necessary to configure
the bounds in some way. Therefore, I added just SetMicroseconds. This
makes the API possible to use and leaves the possibility of adding a
SetPosition in the future.
2021-05-12 15:29:18 +02:00
akif999 428db3cd12 mcp2515: add support for mcp2515 CAN device 2021-05-12 13:37:02 +02:00
deadprogram d7f619ca21 docs: update count of supported devices to 63
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:24:16 +02:00
Kenneth Bell d1ace44754 aht20: add device 2021-05-12 09:21:52 +02:00
Kenneth Bell 6b58fdc95a tester: add a mock for command-oriented i2c devices 2021-05-12 09:21:52 +02:00
Yurii Soldak bd2530abee Example of ssd1306 with 128x64 display over I2C 2021-05-12 09:14:51 +02:00
Yurii Soldak 3bcde1485c Enable reset screen for SSD1306 via I2C 2021-05-12 09:14:51 +02:00
deadprogram 351700e48d 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
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:13:09 +02:00
deadprogram cbcb62af01 wifinina: update docs to simplify the nina-fw update process
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:13:09 +02:00
Yurii Soldak 19bb773e5b fix println + cleanup 2021-05-12 09:11:18 +02:00
Yurii Soldak 69cc0b22c4 Example that connects to AP and prints ip addresses, time and mac 2021-05-12 09:11:18 +02:00
Kenneth Bell 2a48b5c25d wifinina: fix getMACAddress and getTime
Tested against Adafruit AirLift (compatibile variant of wifinina)
2021-05-12 09:11:18 +02:00
deadprogram e6a822f68b docs: up to 62 devices for the README
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-11 18:27:00 +02:00
Kenneth Bell f65bce6d36 ina260: add new i2c device 2021-05-11 11:13:29 +02:00
Yurii Soldak 67b8a341a6 Make TLS work over WiFiNINA
Verified on Arduino Nano33 IoT and nina fw v1.4.5
2021-05-11 10:59:52 +02:00
Tobias Theel b869d27170 remove debug flag and remove unnecessary padding call
(cherry picked from commit 9d3e63232b)
2021-05-11 10:59:52 +02:00
Tobias Theel 107932a201 fix padding and implement missing functions
(cherry picked from commit 0aa0bde76e)
2021-05-11 10:59:52 +02:00
sago35 d2db0c28e2 doc: update README.md 2021-05-10 14:42:12 +02:00
sago35 761bcfc4db pcf8563: add support for pcf8563 real time clock 2021-05-10 14:35:01 +02:00
Kenneth Bell 91dadd5535 Add 16-bit register mock device 2021-05-10 12:15:52 +02:00
Alan Wang f7dc106fc8 tm1637: add support for tm1637 7-segment LED 2021-05-07 18:05:44 +02:00
Ayke van Laethem df343190c2 tone: add package for producing tones using the PWM interface 2021-05-05 14:49:23 +02:00
deadprogram 6bc466f79b pwm: update drivers with PWM to use new interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-05 14:44:24 +02:00
Daniel M. Lambea 23776bf906 flash/drivers: fix EraseBlocks method which is erasing sectors instead 2021-04-05 14:44:56 +02:00
Ayke van Laethem e77e9249cd all: use interfaces for UART objects
This makes it possible to replace UART objects with dummy
implementations, for example. Or allows changing the `machine.UART` type
to `*machine.UART` without breaking compatibility.
2021-04-02 17:31:28 +02:00
Quentin Smith 1345bc2161 p1am: documentation and example program 2021-04-02 17:23:38 +02:00
Quentin Smith ab795cc186 p1am: support the P1AM-100 hardware watchdog 2021-04-02 17:23:38 +02:00
Quentin Smith 36213a1cdc p1am: fetch base controller version number 2021-04-02 17:23:38 +02:00
Quentin Smith 963c903d71 p1am: support discrete inputs and outputs 2021-04-02 17:23:38 +02:00
Quentin Smith 2cec480fb8 p1am: initial driver for the base controller
All the driver can currently do is initialize the base controller and enumerate
the connected modules.
2021-04-02 17:23:38 +02:00
Quentin Smith 68da7f437b p1am: import constants from P1AM Arduino library 2021-04-02 17:23:38 +02:00
sago35 d0632fccfa add .vscode/ to .gitignore 2021-03-28 12:23:16 +02:00
sago35 2c0a74df4d delete .vscode/settings.json 2021-03-28 18:50:51 +09:00
sago35 c6228a0677 Merge remote-tracking branch 'origin/release' into dev 2021-03-28 18:44:35 +09:00
deadprogram 33ec7fc98f examples: correct go fmt error
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:28:41 +01:00
deadprogram 75c15d5d0b build: correct error in Makefile from invalid merge
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:28:12 +01:00
Nerzal e1deb45aac add 4x4 keypad driver (#226)
add 4x4 keypad driver
2021-03-26 18:19:40 +01:00
deadprogram d1cafbc2b2 docs: add missing new drivers added since last release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:12:02 +01:00
Ayke van Laethem 0b6bfda8cf all: do not take the pointer of an I2C object
This is in preparation of PR
https://github.com/tinygo-org/tinygo/pull/1693, which makes machine.I2C0
and similar objects of pointer type, so they can be freely passed
around.
2021-03-26 18:10:39 +01:00
Nerzal 84408279de add 4x4 keypad driver (#226)
add 4x4 keypad driver
2021-03-26 18:10:39 +01:00
deadprogram de1e6a626a Prepare for drivers release 0.15.1 to get tag correct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:10:39 +01:00
deadprogram 7531c9d334 Prepare for drivers release 0.15.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:10:39 +01:00
pleomaxx3002 ee44900c25 DHTXX driver (#235)
dhtXX: add new driver for dht thermometer
2021-03-26 18:09:48 +01:00
deadprogram b9a70aeb6f docs: add missing new drivers added since last release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:05:00 +01:00
deadprogram cad0a320b7 docs: update year in license to 2021
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
Nick Craig-Wood a53a39922b hd44780: add a mode to work with boards where the RW pin is grounded
On some HD44780 boards (eg the Keyestudio LCD1602 expansion shield),
the RW pin isn't brought out and is permanently grounded.

This means that the board can't be read from, and in particular the
busy status can't be read.

This patch adapts the package to work with boards like these.

To signal this to the package, set the RW pin to machine.NoPin.

The package will then disallow all reading and use adjustable timing
based writing. The timing can be adjusted the configuration.
2021-03-26 18:03:15 +01:00
deadprogram 41d6a4c3fa adc: update drivers with ADC to use new config struct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
deadprogram 60ba0e3b30 st7789: correct errors on various godoc comments
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
deadprogram 2b5f43029c st7789: add scrolling functions to match st7735
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
Tobias Theel a771641339 max7219: add driver support 2021-03-26 18:03:15 +01:00
deadprogram 5741ceb9d1 Prepare for drivers release 0.15.1 to get tag correct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-06 13:51:27 +01:00
deadprogram 27ef18930e Prepare for drivers release 0.15.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-06 13:41:58 +01:00
deadprogram e9a6d96ddd docs: update count of supported drivers to add latest contribution
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-05 09:26:56 +01:00
pleomaxx3002 9a7cb1a22f DHTXX driver (#235)
dhtXX: add new driver for dht thermometer
2021-03-05 09:24:45 +01:00
deadprogram d170ec8d81 docs: add missing new drivers added since last release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-05 00:36:50 +01:00
deadprogram 0fc2d28ca8 docs: update year in license to 2021
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-05 00:09:22 +01:00
Nick Craig-Wood ef34c13cc1 hd44780: add a mode to work with boards where the RW pin is grounded
On some HD44780 boards (eg the Keyestudio LCD1602 expansion shield),
the RW pin isn't brought out and is permanently grounded.

This means that the board can't be read from, and in particular the
busy status can't be read.

This patch adapts the package to work with boards like these.

To signal this to the package, set the RW pin to machine.NoPin.

The package will then disallow all reading and use adjustable timing
based writing. The timing can be adjusted the configuration.
2021-02-23 12:28:38 +01:00
deadprogram c64d7920dc adc: update drivers with ADC to use new config struct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-02-01 14:35:51 +01:00
deadprogram 008157b6c9 st7789: correct errors on various godoc comments
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-01-31 16:57:21 +01:00
deadprogram 0ed9683a52 st7789: add scrolling functions to match st7735
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-01-31 16:57:21 +01:00
deadprogram 01acd977f3 microbitmatrix: refactor to eliminate duplicate code with microbit v1/v2
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-01-28 10:09:01 +01:00
deadprogram 231ec57202 microbitmatrix: matrix now working on microbit v2
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-01-28 10:09:01 +01:00
Ayke van Laethem 5d3ad4ba52 all: fix main package in examples
The package with the main function should always have the name main.
This was not the case in three packages.

This was silently allowed before, but since a TinyGo change
(https://github.com/tinygo-org/tinygo/pull/1592) this now results in a
linker failure.

Perhaps this should result in a better error message in TinyGo. However,
the example code also needs to be fixed, so hence this PR.
2021-01-27 23:50:58 +01:00
Roger Peppe 8cb226938b mcp23017: use new tester package
Also change the `tester` package slightly to use an exposed `Registers`
array rather adding yet another accessor method to retrieve a register
value. This seems to me more transparent and "obvious" - we aren't trying
to hide the fact that there's just a simple memory store there.
Also unexport the `assertRegisterRange` method which was never intended
to be part of the public API.
2021-01-20 12:56:22 +01:00
Roger Peppe ce5e443084 mcp23017: implement pin toggling
Also add an example for using multiple devices.
2021-01-20 12:56:22 +01:00
Roger Peppe edf9ba92be mcp23017: new driver for MCP23017 (I2C port expander) 2021-01-20 12:56:22 +01:00
Austen LeBeau c1c05cbef7 Add bmp388 support (#219)
bmp388: add support
2021-01-08 11:32:49 +01:00
Daniel Esteban c338348d2b Better interface "ReadTime" instead of "Time" for DS1307 2020-12-22 08:16:13 +01:00
deadprogram b6aa674b2a test: run unit tests against i2c drivers and any spi drivers without direct gpio
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-12-15 06:08:59 +01:00
deadprogram cc7079b0cd drivers/flash: restore previous calls directly to machine package until we implement SetClockSpeed()
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-12-15 06:08:59 +01:00
deadprogram 42a907035b spi: incorporate change from GH issue feedback
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-12-15 06:08:59 +01:00
deadprogram 46c9ba9595 spi: remove machine.SPI and replace with drivers.SPI interface for almost all SPI drivers
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-12-15 06:08:59 +01:00
Ayke van Laethem df64ce8f50 ws2812: make AVR support more robust
* Merge AVR support for Digispark and non-Digispark
* Fix the error "inline assembly requires more registers than available"
* Use a single file for all AVR targets, in a similar style as the
  Xtensa support.
2020-10-16 18:36:32 +02:00
deadprogram e376785596 Prepare for Drivers release 0.14.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-09-17 10:09:25 +02:00
Amblyopius 4c98d0bc34 - Fix for RAMWR bug:
It can not be skipped as you may call setwindow even if device is not ready for data write to buffer.
Data can only be written if last command was Memory Write or Write Memory Continue which was not guaranteed
There's no performance loss as having the exact same window on a consecutive call is extremely unlikely
- Fixed some typos and added a few missing comments to please go-lint
2020-09-11 11:31:07 +02:00
Ayke van Laethem 65f8299153 ws2812: add support for ESP8266
This patch adds support for the ESP8266 chip by adding support for 80MHz
operation. This should also work when the ESP32 is changed to 80MHz, but
I didn't test it (as there is not currently a way to do that).

Verified on a NodeMCU dev board with an ESP8266.
2020-09-09 22:43:35 +02:00
BCG a689aef543 Renamed NewSpi() to NewSPI() in accordance with Go naming conventions 2020-09-07 09:11:25 +02:00
Ayke van Laethem 7cd7df7bb8 ws2812: add support for the Xtensa architecture
This allows WS2812 LEDs to be controlled by an ESP32. Right now it only
supports 160MHz operation, which is the default with current ESP32
support in TinyGo.
2020-09-05 14:01:22 +02:00
deadprogram 705f474897 adt7410: add connection test and for that matter connection method
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-09-01 13:08:28 +02:00
Jason Striegel ce9c93f228 Add support for setting framerate, vsync pause, and reading scanline data.
- FrameRate option sets device framerates from 39-111Hz
- VSyncLines option adjusts device vsync pause using st7789 "porch control" feature
- Added Rx(cmd, bytes[]) to support retrieving scanline timing data over SPI
- Added Sync functions to support syncronization of animation to vertical scanline timing
- Minor adjustments to Configure to clear screen memory before display is visible
2020-09-01 11:26:06 +02:00
deadprogram db02cbb8a4 i2c: switch all i2c drivers definitions to use i2c bus interface type instead of machine package concrete type
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-29 17:19:27 +02:00
deadprogram a07b20f2f9 tester: correct interface definition for I2C Tx function
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-27 12:17:47 +02:00
deadprogram 4ad210060f lis2mdl: better examples showing how to create unit tests
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-27 12:15:57 +02:00
deadprogram 2ae950e96d tester: improve API surface and implement one more test function in lis2mdl driver
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-27 12:15:57 +02:00
deadprogram dd34b83e9f lis2mdl: starting point for adding unit tests
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-27 12:15:57 +02:00
deadprogram ce81b66fe2 tester: add very basic mock structs for testing i2c devices, based on work done by @rogpeppe
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-27 12:15:57 +02:00
Tim Boldt b1ae52d1b9 Add Waveshare 4.2in B/W e-paper driver (#183)
* waveshare-epd/epd4in2: Add Waveshare 4.2in e-paper driver
2020-08-25 18:57:13 +02:00
sago35 794a9c202f Fix smoke-test unless avr-gcc installed 2020-08-24 13:49:20 +02:00
deadprogram 38f97a8b45 docs: replace README badge for godocs with pkgdocs
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-21 16:17:38 +02:00
deadprogram 35a146d60e lis2mdl: turn on read mode on every read, to ensure that magnetometer data is updated
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-21 10:12:16 +02:00
deadprogram 4f82c06df9 gps: add speed and heading to fix, as parsed from RMC NMEA sentence
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-21 07:24:41 +02:00
Ron Evans af4efceac1 lis2mdl: add LIS2MDL magnetometer (#187)
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-20 13:21:39 +02:00
Ron Evans 5df96c8138 gps: improvements and bugfixes (#186)
* gps: buxfixes and refactoring of API to separate device from parser

Signed-off-by: deadprogram <ron@hybridgroup.com>

* gps: simplify time parser

Signed-off-by: deadprogram <ron@hybridgroup.com>

* gps: add support for RMC sentences

Signed-off-by: deadprogram <ron@hybridgroup.com>

* gps: small renaming to remove reduntant use of word GPS

Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-20 11:22:07 +02:00
Jason Striegel 88aeec9f69 Fix setWindow bug, add CS pin for Clue compatibility. (#180)
* Fix setWindow bug, add CS pin for Clue compatibility.

- corrected bit shift in setWindow that broke high addresses
- added csPin to constructor (will now work with adafruit clue)
- small adjustments and comments to init routine based on working arduino driver

* Update main.go

Updated test example with CS pin.

* Reverting unnecessary (no-effect) change in setRotation.
2020-08-12 08:31:43 +02:00
deadprogram 06b2023b25 Prepare for release v0.13.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-04 16:44:20 +02:00
ardnew 8163dec7c3 ili9341: cache address window to prevent sending unnecessary commands (#171) 2020-08-03 15:58:16 +02:00
sago35 5a75c9c403 Add ILI9341 TFT driver (SPI) for ATSAMD2x (#174)
* ILI9341: Add ILI9341 SPI support for for ATSAMD2x
2020-08-03 12:42:17 +02:00
deadprogram 75b8a75b4b docs: reorder to correct alpha and adjust count of supported drivers
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-03 12:06:17 +02:00
deadprogram 857e45f18d modules: update go version and dependency
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-08-03 11:59:35 +02:00
Ayke van Laethem 9130e61c55 bmi160: add initial support 2020-07-31 19:31:52 +02:00
Alan Wang 68963a1b42 Add Hd44780i2c driver (#173)
* hd44780i2c: add support for hd44780i2c LCD display.
2020-07-31 19:25:56 +02:00
deadprogram 74c9ff4c76 all: changeover to eliminate all direct use of master/slave terminology
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-07-30 12:03:09 +02:00
Alan Wang de27fae9a2 Update ws2812_avr_16m.go 2020-07-16 15:50:07 +02:00
Alan Wang 5ebc7cb09e bmp180: fix temperature type conversion 2020-07-07 23:47:38 +02:00
Yannis Huber 07ca36ac5a tmp102: add Connected func to check for device 2020-07-01 19:25:15 +02:00
Alan Wang 39f44ef478 lsm303agr (#162)
* lsm303agr: add support for lsm303agr digital compass
2020-07-01 16:59:25 +02:00
Daniel Esteban 61874ea928 added custom import path (#161) 2020-06-25 17:11:49 +02:00
BCG f5e81e6a01 Added smoke tests for UDP functionality 2020-06-21 16:21:06 +02:00
BCG 511a3282b7 Added UDP support 2020-06-21 16:21:06 +02:00
Nerdmeister 1d09194bbc Added support for the Bosch BMP280 temperature and pressure sensor. (#158)
* bmp280: Added support for the Bosch BMP280 temperature and pressure sensor.
2020-06-21 16:16:29 +02:00
sago35 941ea4e28b ILI9341 TFT driver (SPI) (#153)
* ili9341: Add spidriver
2020-06-15 18:46:13 +02:00
Ayke van Laethem 21ba9392e2 ci: support Go modules
Since TinyGo started supporting Go modules, there was an error in CI.
The commit 7967e82fed tries to fix that,
but I think the underlying issue is that we're checking out in GOROOT,
which is definitely not a supported configuration.

I think the best solution is to just switch to using Go modules, by
adding a go.mod file in the root. I've set it to Go version 1.13 as that
is the first Go version that supports number literals, but it could be
set to any supported Go version (1.11-1.14).

Since we use Go modules, the location of the drivers checkout should not
matter so I've removed it. This fixes the error on CircleCI.
2020-06-05 08:18:43 +02:00
deadprogram 7967e82fed build: try vendor in working directory to match expected module path
Signed-off-by: deadprogram <ron@hybridgroup.com>
2020-05-28 19:13:46 +02:00
Ayke van Laethem 91539d9ef8 apa102: avoid creating garbage
Avoid creating unnecessary garbage in the following ways:

  * Use the Transfer method instead of the Tx method for single byte
    transfers.
  * Use a statically allocated buffer for the fixed start-of-frame
    sequence.

Running this for a few minutes did not cause the garbage collector to
run. Previously, it would run every second or so in a
persistence-of-vision application.
2020-05-26 19:50:31 +02:00
Alexander Bloss c3f3af5ffa 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
2020-05-16 18:54:41 +02:00
sago35 41694085a1 Improve performance of ILI9341 on ATSAMD5X 2020-05-06 13:25:43 +02:00
Yannis Huber fd9b1ba89b Add SSD1351 OLED display driver (#146)
* ssd1351: Add SSD1351 driver
2020-04-24 07:30:50 +02:00
Ron Evans 9f23761c5e Updates for v0.12.0 release
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-04-13 21:21:45 +02:00
Ron Evans 2ea620026b docs: rearrange list of drivers to be in alpha order
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-04-12 16:34:44 +02:00
Daniel Esteban 04be2320b7 Added HC-SR04 ultrasonic distance sensor. (#143)
* Added HC-SR04 ultrasonic distance sensor.
2020-04-12 16:29:46 +02:00
BCG b1529dcf7a Low-level IO driver for serial flash memory via SPI and QSPI (#124)
* QSPI/SPI: flash memory functions
2020-04-11 17:59:58 +02:00
Ron Evans 1987f424ad mqtt: reduce use of goroutines in router to not start a new goroutine for each invocation of each callback
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-04-11 16:58:37 +02:00
Yannis Huber 6f213e97c3 Add driver for TMP102 low-power digital temperature sensor (#141)
* tmp102: add driver and example
2020-04-03 13:11:46 +02:00
Daniel Esteban ebceed6014 AMG88xx thermal camera module 2020-03-17 12:11:03 +01:00
Ron Evans 08cc84ce48 Updates for version 0.11 release
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-03-07 09:16:59 -08:00
Ron Evans 0c7b6c0d3c docs: update readme to correct count of supported drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-03-07 09:16:08 -08:00
Ron Evans 8b11387d30 license: update year to 2020
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-03-07 09:11:30 -08:00
Ron Evans 41c6e3be0b shifter: simplify API surface for PyBadge (#137)
* shifter: simplify API surface and use build directive to directly match the PyBadge

Signed-off-by: Ron Evans <ron@hybridgroup.com>

* shifter: further simplify API for PyBadge

Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-03-06 07:29:30 +01:00
Daniel Esteban 583e80026a new API for shifter driver.
this doesn't break existing code, but it might no longer work as expected
2020-03-06 01:30:27 +00:00
Jean François CASSAN c7cbd7c6cd Shiftregister implementation (#135)
* Basic support of SIPO shift register

* typo

* add example of shiftregister for arduino and nucleo

* Fix build flag for nucleof103rb

* Fix wrong data pin configuration

* Change README.md for Shift registers

* Add API for individual register's output pin

* Rewrite shift register example to show ShiftPin usage

* Fix target for shiftregister example smoke test

* Fix type in makefile

* Add shiftregister compatble IC

* Edit comment and readme
2020-03-04 18:48:06 +01:00
Ron Evans 12ac4c2c06 mqtt: use buffered channels for incoming messages to handle bursts
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-03-03 09:29:18 +01:00
Ayke van Laethem 6380ad5ed5 semihosting: add example 2020-02-26 19:56:13 +01:00
Daniel Esteban d61fe99ef1 fix typo on StartScanNetworks 2020-02-26 19:55:12 +01:00
Daniel Esteban 8c7eed8d38 some fixes on ili9341 driver 2020-02-24 08:28:15 +01:00
BCG fbe36b62fd Adding scroll functionality for ili9341 (#121)
* ili9341: Adding scroll functionality
2020-02-08 21:12:20 +01:00
Daniel Esteban 0519540d0c fix celsius symbol 2020-02-08 19:54:31 +01:00
Jordan Christiansen 2034f92d11 README: Use degree sign instead of ordinal
º is the masculine ordinal in Spanish. ° is the degree sign. They look different in some fonts.
2020-02-08 19:32:10 +01:00
Ron Evans 850df0a25c release: update for version 0.10.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-01-31 18:43:12 +01:00
Ron Evans 5f4806f0f9 ws2812: work-arounds to allow Digispark to control WS2812 LEDs
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-01-30 14:24:39 +01:00
Daniel Esteban c8e62562b5 added scroll functionality to st7735 2020-01-30 10:20:45 +01:00
Ron Evans 6842bdb424 docs: update README to include list of all 44 drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-01-28 19:27:24 +01:00
BCG d43263f764 Adding driver for four-wire resistive touchscreen (#118)
* resistive: Adding driver for four-wire resistive touchscreen, as used on the Adafruit PyPortal.
2020-01-28 18:55:31 +01:00
BCG 6716bb6c0a ILI9341 TFT driver (#115)
* ILI9341: TFT display implementation
2020-01-07 20:11:46 +01:00
BCG f4bccd1fed Added nrf52840 tag to ws2812 2020-01-06 07:37:21 +01:00
Ron Evans d5aa295b76 l9110x: add support for L9110x h-bridge motor driver
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-01-03 10:37:30 +01:00
Ron Evans c6e8af3057 l293x: added support for h-bridge motor controller
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2020-01-03 10:05:23 +01:00
Ron Evans 38076352eb wifinina: update docs and add Dockerfile to build firmware
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-12-29 17:45:41 +01:00
Ron Evans 086415605e wifinina: update docs and info on how to install WiFiNINA driver
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-12-26 16:34:35 +01:00
BCG 1d0f04af6b Support for ADT7410 temperature sensor (#109)
* ADT7410: add support for i2c temperature sensor
2019-12-26 13:53:06 +01:00
Daniel Esteban dc883d913d remove stxx defaults offsets 2019-12-24 17:36:20 +01:00
Ron Evans 3bb5b4519b docs: correct driver count in README
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-12-23 17:32:07 +01:00
Ron Evans c12f78eb50 Release: v0.9.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-12-23 17:09:00 +01:00
Daniel Esteban adb0c2c261 added generic 8bit shift register (#107)
* shifter: added generic 8bit shift register driver with ShiftPin Pin-compatible GPIO interface
2019-12-22 21:32:49 +01:00
Daniel Esteban 18f0722728 Dual stepper (#101)
* easystepper: added _DualDevice_ to move two motors at the same time
2019-12-22 10:33:02 +01:00
BCG e80a22d0ba Client driver for WiFiNINA firmware (#98)
* wifinina: implementation of WiFiNINA driver, including:
   - TCP client example is working
   - reading sockets and mqtt working
   - switched over to common net package also used by espat package
   - smoke tests and updated README for wifinina
2019-12-22 10:25:10 +01:00
BCG cc5ecafacf Decoupled net package from espat 2019-12-17 22:09:23 +01:00
Ayke van Laethem 7b56e61d52 ws2812: add support for simulation
Call a special __tinygo_ws2812_write_byte function to send a single
byte.
2019-12-14 22:16:41 +01:00
Ayke van Laethem 514b436889 ws2812: fix "invalid symbol redefinition" error
Named local labels shouldn't be used in LLVM because they might get
duplicated resulting in multiple symbol definitions and a compiler
error. Instead, use numeric labels.
2019-12-14 22:11:10 +01:00
BCG 7233452819 Added Feather M0 and Trinket M0 to build tags for WS2812 2019-12-12 14:28:21 +01:00
Ayke van Laethem 7929aa10ea all: add md5sum to smoke tests
This makes it easier to quickly compare all smoke tests for any changes.
2019-12-11 22:13:48 +01:00
Daniel Esteban 02084fd8a5 improvements in st7735/st7789 drivers 2019-12-08 16:38:05 +01:00
Jonathan Basseri f822da51fe Add support for Cortex-M4 120MHz
This adjusts the timing for 120MHz as seen on atsamd51 boards. The
timing was kept as close as possible to the Cortex-M4 64MHz logic in
ws2812_m4_64m.go.

Tested: This works on ItsyBitsy-M4
2019-12-06 11:33:55 +01:00
Jonathan Basseri c62d7db35d Fix number in comment
assembly comment was counting the # of nops.
2019-12-06 11:33:55 +01:00
Ron Evans 93372474a2 release: prepare for v0.8.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-11-26 20:40:16 +01:00
Ron Evans 7dcbfbecc6 espat: implement MQTT subscribe functionality via blocking select/channels.
also refactor response processing for greater speed and efficiency.

Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-11-25 15:56:09 +01:00
Ayke van Laethem 2e606b090a semihosting: initial implementation of ARM semihosting
Useful for logging output to the host console.
2019-11-06 18:53:33 +01:00
Ron Evans e0cdc931e7 mcp3008: add implementation for MCP3008 ADC with SPI interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-31 11:49:49 +01:00
Daniel Esteban 130d9de03b Merge pull request #92 from tinygo-org/st7789-buffer-overflow
st7789: fix index out of bounds error
2019-10-28 12:30:44 +01:00
Ayke van Laethem 2c2f1d3db4 st7789: fix index out of bounds error
This commit adds the same check to the st7789 that also exists in the
st7735.
2019-10-28 12:23:56 +01:00
Ron Evans 2413eb86e0 release: update versions to 0.7.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-17 13:18:24 +02:00
Ron Evans c7555a1469 espat: change all examples to use Arduino Nano33 IoT by default
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-17 13:16:39 +02:00
Ron Evans 3fca96e0ef docs: complete missing GoDocs for main and sub-packages
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-17 11:50:03 +02:00
Ron Evans c7981f72ec core: add Version string for support purposes
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-16 23:23:10 +02:00
Ron Evans 5df157230f lis3dh: example uses I2C1 so requires config to specify pins since they are not default
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-10-16 21:44:58 +02:00
Daniel Esteban bcb291992c ssd1331: make SPI TX faster
same change as PR #89
2019-10-13 02:02:22 +02:00
Daniel Esteban 7b710e3a48 Merge pull request #89 from tinygo-org/st7735-shrink-tx
st7735: make SPI Tx faster
2019-10-11 18:12:20 +02:00
Ayke van Laethem dcfd9c066d st7735: make SPI Tx faster
Most of the ceremony around pin toggling was in fact unnecessary. This
improves performance measurably (rougly 6% in one measurement) and cuts
down on binary size by 80 bytes.
2019-10-10 20:35:50 +02:00
cn 955b3a56e8 veml6070: add Vishay UV light sensor 2019-09-21 10:58:28 +02:00
Ron Evans 21b8d953f4 Update for 0.6.0 release
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-09-09 12:48:57 +02:00
BCG d1b917b835 Support software SPI for APA102 (Itsy Bitsy M0 on-board "Dotstar" LED as example) (#86)
* Added implementation and example to support software-based SPI for APA102, for use with boards like Adafruit Itsy Bitsy M0 for instance.
2019-09-09 12:31:17 +02:00
Ron Evans 2cd73e3204 release: update changelog for 0.5.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-08-26 11:34:59 +02:00
Daniel Esteban 3ae5895183 Initial support for LSM6DS3 IMU (#83)
* Initial support for LSM6DS3 IMU
2019-08-26 08:56:48 +02:00
Ayke van Laethem d80f619c9f ws2812: fix timings for the nrf51
The timings needed to be changed slightly for ws2811 chips which are
slightly slower.
2019-08-19 10:55:00 +02:00
Brad Erickson c91888a099 ws2812: Add build tag for Arduino Nano33 IoT
Uses `arduino_nano33` to handle only this board. Other boards with
the same chip will need a separate tag.
2019-08-15 17:38:27 +02:00
Ron Evans b4dbac3a67 release: update CHANGELOG for v0.4.0 release
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-08-07 15:44:00 +02:00
Daniel Esteban bf077c8249 SSD1331 TFT color display (#77) 2019-08-05 17:54:23 +02:00
Daniel Esteban 4867abcbba added driver for ST7789 TFT color display (#76) 2019-08-05 14:52:39 +02:00
Daniel Esteban 45922f6524 Driver ST7735 for TFT color displays (#72)
* Driver ST7735 for TFT color displays
2019-08-03 11:13:15 +02:00
Daniel Esteban eb040dde9c Merge pull request #78 from conejoninja/typo
typo
2019-08-02 19:57:51 +02:00
Daniel Esteban 04bfa6fa70 typo 2019-08-02 19:49:19 +02:00
Ayke van Laethem 8453611d1f espat: update README with how to install dependencies 2019-07-24 15:48:19 -07:00
Ron Evans d64069a517 release: update CHANGELOG with 0.3.0 release info
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-16 12:14:05 -07:00
Ron Evans e4b80d8e0e espat: add firmware install info for Arduino Nano33 IoT NINA-W102 chip
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-16 12:12:53 -07:00
Ron Evans 50633f3e86 espat: refactor net and tls interface compatible code into separate sub-packages
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 7e78e2c998 espat: add built-in support for MQTT publish using the Paho library packets, alongside some modifications needed for the AT protocol.
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 40d9287ac4 espat: add README with information on how to flash ESP32 or ESP8266 with AT command set firmware.
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 59aece351a espat: change Response() method to use a passed-in timeout value instead of fixed pauses.
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 1b81b992c2 espat: add DialTLS and Dial methods, update MQTT example to allow both MQTT and MQTTS connections
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 506819c93c espat: update MQTT example for greater stability
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 1d9e393948 espat: add example that uses MQTT publish to open server
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 9c88d1fab4 espat: add ResolveUDPAddr and ResolveTCPAddr implementations using AT command for DNS lookup
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans a267fdb8ce espat: improve error handling for key TCP functions
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans 500f3d9813 espat: implement TCPConn using AT command set
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Ron Evans fe58e9b762 espat: use only AT commands that work on both ESP8266 and ESP32
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-15 17:54:26 +02:00
Daniel Esteban d8675515bc epd2in13: added rotation 2019-07-15 01:35:33 +02:00
Daniel Esteban 28dbbe2e65 typo in package name of examples 2019-07-14 22:21:37 +02:00
Ayke van Laethem 78fdaad9c0 mpu6050: properly scale the outputs of the accel/gyro
Units were unspecified before but were in practice the raw output from
the sensor. They have now been changed to sensible outputs
understandable to humans, like the other accelerometers.
2019-07-14 22:20:51 +02:00
Daniel Esteban cb49783f18 Error strings should not be capitalized (unless beginning with proper
nouns or acronyms) or end with punctuation, since they are usually
printed following other context.
2019-07-08 18:52:31 +02:00
Ron Evans 8534e67c83 buzzer: buzzer timbres sound better with more bass
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-06 16:35:09 +02:00
Ron Evans 95755ebae7 buzzer: add simple buzzer implementation
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-06 16:35:09 +02:00
Ron Evans f4583f5144 microphone: PDM MEMS microphone support using I2S interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-07-05 14:52:54 +02:00
Ron Evans 1e59a3970e docs: add note to current/future contributors to please start by opening a GH issue to avoid duplication of efforts
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-06-06 12:12:24 +02:00
Ron Evans e4f6fbcb52 release: update changelog for v0.2.0
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-06-04 07:47:44 +02:00
Ron Evans 7487c6b3a2 docs: correct badge and link in README for godocs to use custom domain
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-06-03 19:45:18 +02:00
Ron Evans d1553458f5 bme280: add package docs, and add bme280 to README
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-06-03 19:39:30 +02:00
Daniel Esteban 79d3609f76 Support for AT24C32/64 2-wire serial EEPROM 2019-06-03 19:38:04 +02:00
Ayke van Laethem 00a9b9db77 ws2812: better support the nrf52832
This has cost me _hours_ to find. There are many clones of the ws2812
and they have slightly different timing characteristics. Some don't work
so well when you get close to the minimum T1H time: a 1-bit may be
interpreted as a 0-bit.
2019-06-03 19:25:24 +02:00
Martin Treml f68388702d Implementation of the BME280 Sensor (#38)
* Driver for bme280
2019-06-03 19:03:53 +02:00
Ron Evans 0722fe7161 docs: add CHANGELOG for first official release of drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-29 16:28:08 +02:00
Ron Evans c09f0a8075 all: switch to using custom domain for all drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-29 13:33:50 +02:00
Ron Evans 7757122598 docs: add contribution guidelines link to README and also show dev branch status in CI build
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 08:58:41 +02:00
Ron Evans 93849555f3 docs: add contribution guidelines to repo
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 08:54:36 +02:00
Ron Evans 3f946868e1 all: refactor all current drivers to use new machine.Pin interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-26 21:46:33 +02:00
Daniel Esteban 2c0bde0dad microbitmatrix: fix for dev branch / volatile package/API (#63)
* microbitmatrix: fix for dev branch / volatile package/API
2019-05-25 18:02:47 +02:00
Ron Evans 848385d625 docs: just to make clear what the driver is for
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-24 15:52:47 +02:00
k-brk dce063e0c2 Support for DS1307 (#58)
* Support for DS1307
2019-05-24 12:56:26 +02:00
Daniel Esteban 30b118cf63 support for Waveshare EPD 2.13" display (black&white only) (#61)
* support for Waveshare EPD 2.13" display (black&white only)
2019-05-24 12:37:02 +02:00
Ron Evans 9127719933 docs: add GPS to README
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-23 15:36:00 +02:00
Anthony Elder a24657d1eb GPS driver (#55)
* u-blox GPS driver for both I2C and UART
2019-05-23 15:29:29 +02:00
Ron Evans c259da1f17 build: use Makefile test command for CI tests
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-17 21:16:13 +02:00
Daniel Esteban 374d3f6bec Support for Waveshare 2.13" (B & C versions) e-paper display (#56)
* Support for Waveshare 2.13" (B) e-paper display
2019-05-17 07:55:57 +02:00
Anthony Elder 5930c149d9 SHT3x driver (#53)
* SHT3x driver
2019-05-12 16:11:15 +02:00
Daniel Esteban d22cf7a3e1 Driver for BBC micro:bit on-board LED matrix (#48) 2019-05-05 16:51:04 +02:00
Ron Evans a9e5c8f710 build: use tinygo-dev docker container for CI
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-05 16:28:38 +02:00
Daniel Esteban ad2b76be8b support for SSD1306 displays using I2C or SPI, several screen sizes (#49)
supported too
2019-05-05 11:45:26 +02:00
k-brk ba4de1efb8 SetPixel removed, formatting 2019-05-05 11:42:38 +02:00
k-brk 4560c61c61 GPIO implements io readwriter interface, simplified display, smoke tests 2019-05-05 11:42:38 +02:00
k-brk 715829cdbd Support for HD44780 in 4 and 8 bit mode 2019-05-05 11:42:38 +02:00
Ron Evans 8ac1fa2b22 adxl345: update ADXL345 driver and example to make uniform with other accelerometers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-03 20:30:03 +02:00
Ron Evans b7fe897b8c mag3110: change method name/signature for obtaining temperature to be uniform with other similar drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-03 20:26:43 +02:00
Daniel Esteban 35a7590c2d clean commit, added smoke tests 2019-05-03 11:44:56 +02:00
Ron Evans de22b8839e ci: ensure all examples are included in smoke tests
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-26 09:28:16 +02:00
Daniel Esteban 38e0d39f48 Initial support for RGB led matrix, usually called hub75 2019-04-26 09:24:08 +02:00
Ron Evans 59db5fef76 thermistor: add support for thermistors such as the NTC 3950
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-25 11:30:10 +02:00
Ron Evans c0cadf8d82 lis3dh: implement accelerometer functionality
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-24 20:10:57 +02:00
Ron Evans 720097ebad ci: perform go fmt test on all files
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-24 19:07:41 +02:00
Daniel Esteban 772a1044c4 Define common display interface (#31)
* issue #27 definition of Displayer interface
2019-04-24 18:56:49 +02:00
Ron Evans cd992bd7d6 bmp180: change method names/signature for obtaining temperature and pressure uniform with other similar drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-24 15:17:26 +02:00
Ron Evans f6b9080f9e ci: show CircleCI badge in README
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 22:21:30 +02:00
Ron Evans 137e667d5a ci: setup CircleCI to build an example per driver as a smoke test suite
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 22:16:47 +02:00
Ron Evans cc391102ff ci: put CircleCI config file under correct name
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 19:01:31 +02:00
Ron Evans df3b3aa1ca ci: first start at setting up CircleCI for smoke tests
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 19:00:40 +02:00
Ron Evans 84b1cd0bfb docs: improve godocs formatting
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 11:12:28 +02:00
Ron Evans 8e384a00f1 docs: improve godocs formatting
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 11:11:28 +02:00
Ron Evans 7006a675ad docs: improve godocs formatting
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 11:10:11 +02:00
Ron Evans 1895c84912 docs: improve godocs info used by main package to explain what the package is and how to use it properly
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 11:07:43 +02:00
Ron Evans 3c68510cbc docs: improve godocs info used by main package to explain what the package is and how to use it
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-22 10:56:22 +02:00
Daniel Esteban a332118087 added DS3231 driver to README.md 2019-04-08 08:18:42 +02:00
Daniel Esteban ed2d334d55 Driver for ADXL345 3-axis digital accelerometer (#33)
* Driver for ADXL345 3-axis digital accelerometer
2019-04-08 08:18:03 +02:00
Daniel Esteban f6bdc9734f ds3231: basic support for DS3231 RTC device 2019-04-07 16:55:46 +02:00
Ron Evans d9b426b90b i2c: refactor all i2c drivers to use Address property of Driver. Allows variations to override the default address as discussed in #14 (#30)
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-04-07 10:50:34 +02:00
Ron Evans b8e278e08f examples: add example code for BlinkM
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-03-14 16:34:11 +01:00
Ayke van Laethem b0c4f3e2ce mma8653: return acceleration in a standard unit: micro-G. 2019-03-11 17:14:04 +01:00
Ron Evans c83475d09d docs: add VL53L1X to list of supported devices
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-03-06 17:49:37 +01:00
Daniel Esteban f144bfed79 Basic support for VL53L1X time-of-flight distance sensor (#20)
* Basic support for VL53L1X time-of-flight distance sensor
2019-03-06 17:42:17 +01:00
Ron Evans 8e1df6d63a examples: add basic usage example for mma8653
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-03-04 21:42:02 +01:00
Ron Evans 239c10a6ab examples: add example for mag3110 magnetometer
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-03-04 21:33:32 +01:00
Ron Evans 55d12ce0a1 examples: add basic usage example for ws2812
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-28 14:22:14 +01:00
Ayke van Laethem 7116778235 ws2812: add support for M0 at 48MHz: most SAMD21 boards 2019-02-24 23:10:10 +01:00
Ron Evans 0f7b458d9c docs: update README for current list of drivers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-24 13:33:40 +01:00
Ron Evans 0c2924cd77 espat: add support for esp8266/esp32 Wifi adaptor AT command set with net-compatible UDP support
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-24 12:54:11 +01:00
Daniel Esteban ae53ea7d81 easystepper: very simple 4-wire stepper driver 2019-02-23 13:41:52 +01:00
Ayke van Laethem 4ff437e5d4 ws2812: add nrf52 support, update timings for m0 and avr
This commit adds support for the nrf52, which is a Cortex-M4 running at
64MHz.
While implementing this, I discovered that the timings for AVR/16MHz and
Cortex-M0 at 16MHz weren't quite right. They do work, but were slightly
out of spec. So I fixed this as well.
2019-02-22 07:10:22 +01:00
Ron Evans 1475a63798 docs: add BH1750 to README
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-08 09:10:02 +01:00
Daniel Esteban 693e7a1db7 Added driver for BH1750 digital ambient light sensor (#15)
* Added driver for BH1750 digital ambient light sensor
2019-02-08 09:04:58 +01:00
Ron Evans 31bc74101d examples: add example for apa102 (#17)
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-07 14:52:05 +01:00
Ron Evans 7dfd72c1b1 examples: add example for mpu6050 (#16)
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-07 14:51:45 +01:00
Ron Evans bb56d49ce3 rename: make sure package name is consistent in all places after move to organization
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-07 09:41:24 +01:00
Ron Evans 96b5daee8e license: add BSD-3 license for the TinyGo Authors
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-07 09:18:27 +01:00
Ron Evans be048a35bf docs: commit initial version of README file
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-02-07 08:35:07 +01:00
Daniel Esteban 3af2f18437 Initial support for BMP180 digital pressure sensor (#11)
* Initial support for BMP180 digital pressure sensor
Note that Pressure & Temperature return int32 and millis unit (millidegrees
and mPa)
2019-02-06 08:50:40 +01:00
Ron Evans 773b01e911 apa102: add support for APA102 SPI controlled LEDs
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2018-12-22 19:14:02 +01:00
500 changed files with 80369 additions and 163 deletions
+20
View File
@@ -0,0 +1,20 @@
# Golang CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
version: 2
jobs:
build:
docker:
- image: tinygo/tinygo-dev
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
+2
View File
@@ -0,0 +1,2 @@
build
.vscode/
+390
View File
@@ -0,0 +1,390 @@
0.19.0
---
- **new devices**
- ft6336: add support for ft6336
- pca9685: PCA9685 driver
- shtc3: Sensirion SHTC3 Relative Humidity / Temperature i2c sensor
- sx126x: Driver for Semtech sx126x radio modules
- xpt2046: XPT2046 Touch driver (#350)
- **enhancements**
- **hd44780i2c**
- clean up for go fmt
- Needed fixes and update hd44780i2c.go
- **ili9341, ili9342**
- add support for m5stack
- add support for m5stack-core2
- **wifi**
- modify to use shared net.Adapter interface for all supported wifi devices
- wifinina: remove busy wait
- **bugfixes**
- **hd44780**
- fix 4-bit data length flag
- Reset data pins to output mode after reading
- Nano 33 BLE drivers (#351)
- **docs**
- examples/wifi: add unified example for tcpclient that compiles for all supported wifi adaptors
0.18.0
---
- **new devices**
- 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**
- hcsr04: Added HC-SR04 ultrasonic distance sensor. (#143)
- spi/qspi: Low-level IO driver for serial flash memory via SPI and QSPI (#124)
- tmp102: TMP102 low-power digital temperature sensor (#141)
- amg88xx: AMG88xx thermal camera module
- **bugfixes**
- mqtt: reduce use of goroutines in router to not start a new goroutine for each invocation of each callback
0.11.0
---
- **new devices**
- shiftregister: Support for various shift register chips (#135)
- **enhancements**
- shifter: simplify API surface for PyBadge (#137)
- shifter: new API for shifter driver
- mqtt: use buffered channels for incoming messages to handle bursts
- ili9341: Adding scroll functionality (#121)
- **bugfixes**
- wifinina: fix typo on StartScanNetworks
- ili9341: various bugfixes for display
- **examples**
- semihosting: add example
- **docs**
- readme: Use degree sign instead of ordinal
- all: fix celsius symbol in all code comments
0.10.0
---
- **new devices**
- adt7410: Support for ADT7410 temperature sensor (#109)
- ili9341: ILI9341 TFT driver (#115)
- l293x: added support for h-bridge motor controller
- l9110x: add support for L9110x h-bridge motor driver
- resistive: Adding driver for four-wire resistive touchscreen (#118)
- **enhancements**
- st7735: added scroll functionality to st7735
- st7735: remove default offsets
- st7789: remove default offsets
- ws2812: Added nrf52840 tag to ws2812
- ws2812: work-arounds to allow Digispark to control WS2812 LEDs
- **docs**
- readme: update README to include list of all 44 drivers
- wifinina: update docs and add Dockerfile to build firmware
- wifinina: update docs and info on how to install WiFiNINA driver
0.9.0
---
- **new devices**
- net: shared implementation of net package for serial wifi devices
- shifter: add support for bit Parallel In Serial Out (PISO) shifter
- stepper: add support for dual stepper motor
- wifinina: add implementation for WiFiNINA firmware
- **enhancements**
- st7735: improvements in st7735 driver
- st7789: improvements in st7789 driver
- ws2812: add support for 120Mhz Cortex-M4
- ws2812: added Feather M0 and Trinket M0 to build tags for WS2812
- ws2812: add support for simulation
- **bugfixes**
- ws2812: fix "invalid symbol redefinition" error
- **examples**
- Add examples for wifinina drivers
0.8.0
---
- **new devices**
- mcp3008: add implementation for MCP3008 ADC with SPI interface
- semihosting: initial implementation of ARM semihosting
- **enhancements**
- espat: refactor response processing for greater speed and efficiency
- espat: implement mqtt subscribe functionality via blocking select/channels (experiemental)
- **bugfixes**
- st7789: fix index out of bounds error
- **examples**
- Add espat driver example for mqtt subscribe
0.7.0
---
- **new devices**
- veml6070: add Vishay UV light sensor
- **enhancements**
- lis3dh: example uses I2C1 so requires config to specify pins since they are not default
- ssd1331: make SPI TX faster
- st7735: make SPI Tx faster
- **docs**
- complete missing GoDocs for main and sub-packages
- **core**
- add Version string for support purposes
- **examples**
- Change all espat driver examples to use Arduino Nano33 IoT by default
0.6.0
---
- **new devices**
- Support software SPI for APA102 (Itsy Bitsy M0 on-board "Dotstar" LED as example)
0.5.0
---
- **new devices**
- LSM6DS3 accelerometer
- **bugfixes**
- ws2812: fix timings for the nrf51
- **enhancements**
- ws2812: Add build tag for Arduino Nano33 IoT
0.4.0
---
- **new devices**
- SSD1331 TFT color display
- ST7735 TFT color display
- ST7789 TFT color display
- **docs**
- espat
- complete list of dependencies for flashing NINA-W102 as used in Arduino Nano33 IoT board.
0.3.0
---
- **new devices**
- Buzzer for piezo or small speaker
- PDM MEMS microphone support using I2S interface
- **enhancements**
- epd2in13: added rotation
- espat
- add built-in support for MQTT publish using the Paho library packets, alongside some modifications needed for the AT protocol.
- add DialTLS and Dial methods, update MQTT example to allow both MQTT and MQTTS connections
- add example that uses MQTT publish to open server
- add README with information on how to flash ESP32 or ESP8266 with AT command set firmware.
- add ResolveUDPAddr and ResolveTCPAddr implementations using AT command for DNS lookup
- change Response() method to use a passed-in timeout value instead of fixed pauses.
- implement TCPConn using AT command set
- improve error handling for key TCP functions
- refactor net and tls interface compatible code into separate sub-packages
- update MQTT example for greater stability
- use only AT commands that work on both ESP8266 and ESP32
- add documentation on how to use Arduino Nano33 IoT built-in WiFi NINA-W102 chip.
- **bugfixes**
- core: Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context.
- docs: add note to current/future contributors to please start by opening a GH issue to avoid duplication of efforts
- examples: typo in package name of examples
- mpu6050: properly scale the outputs of the accel/gyro
0.2.0
---
- **new devices**
- AT24C32/64 2-wire serial EEPROM
- BME280 humidity/pressure sensor
- **bugfixes**
- ws2812: better support for nrf52832
0.1.0
---
- **first release**
- This is the first official release of the TinyGo drivers repo, matching TinyGo 0.6.0. The following devices are supported:
- ADXL345
- APA102
- BH1750
- BlinkM
- BMP180
- DS1307
- DS3231
- Easystepper
- ESP8266/ESP32
- GPS
- HUB75
- LIS3DH
- MAG3110
- microbit LED matrix
- MMA8653
- MPU6050
- PCD8544
- SHT3x
- SSD1306
- Thermistor
- VL53L1X
- Waveshare 2.13"
- Waveshare 2.13" (B & C)
- WS2812
+40
View File
@@ -0,0 +1,40 @@
# How to contribute
Thank you for your interest in improving the TinyGo drivers.
We would like your help to make this project better, so we appreciate any contributions. See if one of the following descriptions matches your situation:
### New to TinyGo
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
### One of the TinyGo drivers is not working as you expect
Please open a Github issue with your problem, and we will be happy to assist.
### Some specific hardware you want to use does not appear to be in the TinyGo drivers
We probably have not implemented it yet. Your contribution adding the hardware support to TinyGo would be greatly appreciated.
Please first open a Github issue. We want to help, and also make sure that there is no duplications of efforts. Sometimes what you need is already being worked on by someone else.
## How to use our Github repository
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:
- Fork repo
- Create a feature branch off of the `dev` branch
- Make some useful change
- Make sure the tests still pass
- Submit a pull request against the `dev` branch.
- Be kind
## How to run tests
To run the tests:
```
make test
```
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+242
View File
@@ -0,0 +1,242 @@
clean:
@rm -rf build
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
smoke-test:
@mkdir -p build
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adt7410/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adxl345/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/amg88xx
@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
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bh1750/main.go
@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
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/ds3231/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/easystepper/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/espconsole/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/esphub/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/espstation/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/flash/console/spi
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/flash/console/qspi
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/i2c/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/uart/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/hcsr04/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/customchar/main.go
@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
@md5sum ./build/test.hex
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
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go
@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
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/vl53l1x/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13/main.go
@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
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/buzzer/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/veml6070/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/simple/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/speed/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/simple/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/speed/main.go
@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
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
@md5sum ./build/test.uf2
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/basic/
@md5sum ./build/test.elf
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/touchpaint/
@md5sum ./build/test.elf
tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/sx126x/lora_rxtx/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/ssd1289/main.go
@md5sum ./build/test.uf2
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 xpt2046 \
ft6336 sx126x ssd1289
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
unit-test:
@go test -v $(addprefix ./,$(TESTS))
test: clean fmt-check unit-test smoke-test
+148
View File
@@ -0,0 +1,148 @@
# TinyGo Drivers
[![PkgGoDev](https://pkg.go.dev/badge/tinygo.org/x/drivers)](https://pkg.go.dev/tinygo.org/x/drivers) [![CircleCI](https://circleci.com/gh/tinygo-org/drivers/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
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
```shell
go get tinygo.org/x/drivers
```
## How to use
Here is an example in TinyGo that uses the BMP180 digital barometer:
```go
package main
import (
"time"
"machine"
"tinygo.org/x/drivers/bmp180"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := bmp180.New(machine.I2C0)
sensor.Configure()
connected := sensor.Connected()
if !connected {
println("BMP180 not detected")
return
}
println("BMP180 detected")
for {
temp, _ := sensor.ReadTemperature()
println("Temperature:", float32(temp)/1000, "°C")
pressure, _ := sensor.ReadPressure()
println("Pressure", float32(pressure)/100000, "hPa")
time.Sleep(2 * time.Second)
}
}
```
## Currently supported devices
The following 78 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 |
| [FT6336 touch controller](https://focuslcds.com/content/FT6236.pdf) | I2C |
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
| [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO |
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
| [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/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
| [SHTC3 Digital Humidity Sensor (RH/T)](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf) | I2C |
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
| [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 |
| [XPT2046 touch controller](http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) | GPIO |
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-transceiv-ers/sx1261) | SPI |
| [SSD1289 TFT color display](http://aitendo3.sakura.ne.jp/aitendo_data/product_img/lcd/tft2/M032C1289TP/3.2-SSD1289.pdf) | GPIO |
## Contributing
Your contributions are welcome!
Please take a look at our [CONTRIBUTING.md](./CONTRIBUTING.md) document for details.
## License
This project is licensed under the BSD 3-clause license, just like the [Go project](https://golang.org/LICENSE) itself.
+92
View File
@@ -0,0 +1,92 @@
// 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 (
"time"
"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 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 drivers.I2C) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 2),
Address: Address,
}
}
// Configure the ADT7410 device.
func (d *Device) Configure() (err error) {
// reset the chip
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)
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 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.
func (d *Device) ReadTempF() float32 {
return d.ReadTempC()*1.8 + 32.0
}
func (d *Device) writeByte(reg uint8, data byte) {
d.buf[0] = reg
d.buf[1] = data
d.bus.Tx(uint16(d.Address), d.buf, nil)
}
func (d *Device) readByte(reg uint8) byte {
d.bus.ReadRegister(d.Address, reg, d.buf)
return d.buf[0]
}
func (d *Device) readUint16(reg uint8) uint16 {
d.bus.ReadRegister(d.Address, reg, d.buf)
return uint16(d.buf[0])<<8 | uint16(d.buf[1])
}
+49
View File
@@ -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,
}
}
+70
View File
@@ -0,0 +1,70 @@
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 (
// 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
// Temperature Value LSB Register
RegTempValueLSB = 0x1
// Status Register
RegStatus = 0x2
// Config Register
RegConfig = 0x3
// 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
RegReset = 0x2F
)
+193
View File
@@ -0,0 +1,193 @@
// Package adxl345 provides a driver for the ADXL345 digital accelerometer.
//
// Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
//
// Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
//
package adxl345 // import "tinygo.org/x/drivers/adxl345"
import "tinygo.org/x/drivers"
type Range uint8
type Rate uint8
// Internal structure for the power configuration
type powerCtl struct {
link uint8
autoSleep uint8
measure uint8
sleep uint8
wakeUp uint8
}
// Internal structure for the sensor's data format configuration
type dataFormat struct {
selfTest uint8
spi uint8
intInvert uint8
fullRes uint8
justify uint8
sensorRange Range
}
// Internal structure for the sampling rate configuration
type bwRate struct {
lowPower uint8
rate Rate
}
// Device wraps an I2C connection to a ADXL345 device.
type Device struct {
bus drivers.I2C
Address uint16
powerCtl powerCtl
dataFormat dataFormat
bwRate bwRate
}
// New creates a new ADXL345 connection. The I2C bus must already be
// configured.
//
// 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 drivers.I2C) Device {
return Device{
bus: bus,
powerCtl: powerCtl{
measure: 1,
},
dataFormat: dataFormat{
sensorRange: RANGE_2G,
},
bwRate: bwRate{
lowPower: 1,
rate: RATE_100HZ,
},
Address: AddressLow,
}
}
// Configure sets up the device for communication
func (d *Device) Configure() {
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
}
// Halt stops the sensor, values will not updated
func (d *Device) Halt() {
d.powerCtl.measure = 0
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
}
// Restart makes reading the sensor working again after a halt
func (d *Device) Restart() {
d.powerCtl.measure = 1
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
}
// ReadAcceleration reads the current acceleration from the device and returns
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
rx, ry, rz := d.ReadRawAcceleration()
x = d.dataFormat.convertToIS(rx)
y = d.dataFormat.convertToIS(ry)
z = d.dataFormat.convertToIS(rz)
return
}
// ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis
// from the adxl345.
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
data := []byte{0, 0, 0, 0, 0, 0}
d.bus.ReadRegister(uint8(d.Address), REG_DATAX0, data)
x = readIntLE(data[0], data[1])
y = readIntLE(data[2], data[3])
z = readIntLE(data[4], data[5])
return
}
// UseLowPower sets the ADXL345 to use the low power mode.
func (d *Device) UseLowPower(power bool) {
if power {
d.bwRate.lowPower = 1
} else {
d.bwRate.lowPower = 0
}
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
}
// SetRate change the current rate of the sensor
func (d *Device) SetRate(rate Rate) bool {
d.bwRate.rate = rate & 0x0F
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
return true
}
// SetRange change the current range of the sensor
func (d *Device) SetRange(sensorRange Range) bool {
d.dataFormat.sensorRange = sensorRange & 0x03
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
return true
}
// convertToIS adjusts the raw values from the adxl345 with the range configuration
func (d *dataFormat) convertToIS(rawValue int32) int32 {
switch d.sensorRange {
case RANGE_2G:
return rawValue * 4 // rawValue * 2 * 1000 / 512
case RANGE_4G:
return rawValue * 8 // rawValue * 4 * 1000 / 512
case RANGE_8G:
return rawValue * 16 // rawValue * 8 * 1000 / 512
case RANGE_16G:
return rawValue * 32 // rawValue * 16 * 1000 / 512
default:
return 0
}
}
// toByte returns a byte from the powerCtl configuration
func (p *powerCtl) toByte() (bits uint8) {
bits = 0x00
bits = bits | (p.link << 5)
bits = bits | (p.autoSleep << 4)
bits = bits | (p.measure << 3)
bits = bits | (p.sleep << 2)
bits = bits | p.wakeUp
return bits
}
// toByte returns a byte from the dataFormat configuration
func (d *dataFormat) toByte() (bits uint8) {
bits = 0x00
bits = bits | (d.selfTest << 7)
bits = bits | (d.spi << 6)
bits = bits | (d.intInvert << 5)
bits = bits | (d.fullRes << 3)
bits = bits | (d.justify << 2)
bits = bits | uint8(d.sensorRange)
return bits
}
// toByte returns a byte from the bwRate configuration
func (b *bwRate) toByte() (bits uint8) {
bits = 0x00
bits = bits | (b.lowPower << 4)
bits = bits | uint8(b.rate)
return bits
}
// readInt converts two bytes to int16
func readIntLE(msb byte, lsb byte) int32 {
return int32(uint16(msb) | uint16(lsb)<<8)
}
+61
View File
@@ -0,0 +1,61 @@
package adxl345
const AddressLow = 0x53
const AddressHigh = 0x1D
const (
// Data rate
RATE_3200HZ Rate = 0x0F // 3200 Hz
RATE_1600HZ Rate = 0x0E // 1600 Hz
RATE_800HZ Rate = 0x0D // 800 Hz
RATE_400HZ Rate = 0x0C // 400 Hz
RATE_200HZ Rate = 0x0B // 200 Hz
RATE_100HZ Rate = 0x0A // 100 Hz
RATE_50HZ Rate = 0x09 // 50 Hz
RATE_25HZ Rate = 0x08 // 25 Hz
RATE_12_5HZ Rate = 0x07 // 12.5 Hz
RATE_6_25HZ Rate = 0x06 // 6.25 Hz
RATE_3_13HZ Rate = 0x05 // 3.13 Hz
RATE_1_56HZ Rate = 0x04 // 1.56 Hz
RATE_0_78HZ Rate = 0x03 // 0.78 Hz
RATE_0_39HZ Rate = 0x02 // 0.39 Hz
RATE_0_20HZ Rate = 0x01 // 0.20 Hz
RATE_0_10HZ Rate = 0x00 // 0.10 Hz
// Data range
RANGE_2G Range = 0x00 // +-2 g
RANGE_4G Range = 0x01 // +-4 g
RANGE_8G Range = 0x02 // +-8 g
RANGE_16G Range = 0x03 // +-16 g)
REG_DEVID = 0x00 // R, 11100101, Device ID
REG_THRESH_TAP = 0x1D // R/W, 00000000, Tap threshold
REG_OFSX = 0x1E // R/W, 00000000, X-axis offset
REG_OFSY = 0x1F // R/W, 00000000, Y-axis offset
REG_OFSZ = 0x20 // R/W, 00000000, Z-axis offset
REG_DUR = 0x21 // R/W, 00000000, Tap duration
REG_LATENT = 0x22 // R/W, 00000000, Tap latency
REG_WINDOW = 0x23 // R/W, 00000000, Tap window
REG_THRESH_ACT = 0x24 // R/W, 00000000, Activity threshold
REG_THRESH_INACT = 0x25 // R/W, 00000000, Inactivity threshold
REG_TIME_INACT = 0x26 // R/W, 00000000, Inactivity time
REG_ACT_INACT_CTL = 0x27 // R/W, 00000000, Axis enable control for activity and inactiv ity detection
REG_THRESH_FF = 0x28 // R/W, 00000000, Free-fall threshold
REG_TIME_FF = 0x29 // R/W, 00000000, Free-fall time
REG_TAP_AXES = 0x2A // R/W, 00000000, Axis control for single tap/double tap
REG_ACT_TAP_STATUS = 0x2B // R, 00000000, Source of single tap/double tap
REG_BW_RATE = 0x2C // R/W, 00001010, Data rate and power mode control
REG_POWER_CTL = 0x2D // R/W, 00000000, Power-saving features control
REG_INT_ENABLE = 0x2E // R/W, 00000000, Interrupt enable control
REG_INT_MAP = 0x2F // R/W, 00000000, Interrupt mapping control
REG_INT_SOUCE = 0x30 // R, 00000010, Source of interrupts
REG_DATA_FORMAT = 0x31 // R/W, 00000000, Data format control
REG_DATAX0 = 0x32 // R, 00000000, X-Axis Data 0
REG_DATAX1 = 0x33 // R, 00000000, X-Axis Data 1
REG_DATAY0 = 0x34 // R, 00000000, Y-Axis Data 0
REG_DATAY1 = 0x35 // R, 00000000, Y-Axis Data 1
REG_DATAZ0 = 0x36 // R, 00000000, Z-Axis Data 0
REG_DATAZ1 = 0x37 // R, 00000000, Z-Axis Data 1
REG_FIFO_CTL = 0x38 // R/W, 00000000, FIFO control
REG_FIFO_STATUS = 0x39 // R, 00000000, FIFO status
)
+108
View File
@@ -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
}
+74
View File
@@ -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},
},
}
}
+20
View File
@@ -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")
)
+159
View File
@@ -0,0 +1,159 @@
// Package amg88xx provides a driver for the AMG88XX Thermal Camera
//
// Datasheet:
// https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf
package amg88xx // import "tinygo.org/x/drivers/amg88xx"
import (
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a AMG88xx device.
type Device struct {
bus drivers.I2C
Address uint16
data []uint8
interruptMode InterruptMode
interruptEnable uint8
}
type InterruptMode uint8
type Config struct {
}
// New creates a new AMG88xx 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: AddressHigh,
}
}
// Configure sets up the device for communication
func (d *Device) Configure(cfg Config) {
d.data = make([]uint8, 128)
d.SetPCTL(NORMAL_MODE)
d.SetReset(INITIAL_RESET)
d.SetFrameRate(FPS_10)
time.Sleep(100 * time.Millisecond)
}
// ReadPixels returns the 64 values (8x8 grid) of the sensor converted to millicelsius
func (d *Device) ReadPixels(buffer *[64]int16) {
d.bus.ReadRegister(uint8(d.Address), PIXEL_OFFSET, d.data)
for i := 0; i < 64; i++ {
buffer[i] = int16((uint16(d.data[2*i+1]) << 8) | uint16(d.data[2*i]))
if (buffer[i] & (1 << 11)) > 0 { // temperature negative
buffer[i] &= ^(1 << 11)
buffer[i] = -buffer[i]
}
buffer[i] *= PIXEL_TEMP_CONVERSION
}
}
// SetPCTL sets the PCTL
func (d *Device) SetPCTL(pctl uint8) {
d.bus.WriteRegister(uint8(d.Address), PCTL, []byte{pctl})
}
// SetReset sets the reset value
func (d *Device) SetReset(rst uint8) {
d.bus.WriteRegister(uint8(d.Address), RST, []byte{rst})
}
// SetFrameRate configures the frame rate
func (d *Device) SetFrameRate(framerate uint8) {
d.bus.WriteRegister(uint8(d.Address), FPSC, []byte{framerate & 0x01})
}
// SetMovingAverageMode sets the moving average mode
func (d *Device) SetMovingAverageMode(mode bool) {
var value uint8
if mode {
value = 1
}
d.bus.WriteRegister(uint8(d.Address), AVE, []byte{value << 5})
}
// SetInterruptLevels sets the interrupt levels
func (d *Device) SetInterruptLevels(high int16, low int16) {
d.SetInterruptLevelsHysteresis(high, low, (high*95)/100)
}
// SetInterruptLevelsHysteresis sets the interrupt levels with hysteresis
func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis int16) {
high = high / PIXEL_TEMP_CONVERSION
if high < -4095 {
high = -4095
}
if high > 4095 {
high = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
low = low / PIXEL_TEMP_CONVERSION
if low < -4095 {
low = -4095
}
if low > 4095 {
low = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
hysteresis = hysteresis / PIXEL_TEMP_CONVERSION
if hysteresis < -4095 {
hysteresis = -4095
}
if hysteresis > 4095 {
hysteresis = 4095
}
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
}
// EnableInterrupt enables the interrupt pin on the device
func (d *Device) EnableInterrupt() {
d.interruptEnable = 1
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// DisableInterrupt disables the interrupt pin on the device
func (d *Device) DisableInterrupt() {
d.interruptEnable = 0
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// SetInterruptMode sets the interrupt mode
func (d *Device) SetInterruptMode(mode InterruptMode) {
d.interruptMode = mode
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
}
// GetInterrupt reads the state of the triggered interrupts
func (d *Device) GetInterrupt() []uint8 {
data := make([]uint8, 8)
d.bus.ReadRegister(uint8(d.Address), INT_OFFSET, data)
return data
}
// ClearInterrupt clears any triggered interrupts
func (d *Device) ClearInterrupt() {
d.SetReset(FLAG_RESET)
}
// ReadThermistor reads the onboard thermistor
func (d *Device) ReadThermistor() int16 {
data := make([]uint8, 2)
d.bus.ReadRegister(uint8(d.Address), TTHL, data)
return (int16((uint16(data[1])<<8)|uint16(data[0])) * THERMISTOR_CONVERSION) / 10
}
+46
View File
@@ -0,0 +1,46 @@
package amg88xx
// The I2C address which this device listens to.
const AddressHigh = 0x69
const AddressLow = 0x68
const (
PCTL = 0x00
RST = 0x01
FPSC = 0x02
INTC = 0x03
STAT = 0x04
SCLR = 0x05
AVE = 0x07
INTHL = 0x08
INTHH = 0x09
INTLL = 0x0A
INTLH = 0x0B
IHYSL = 0x0C
IHYSH = 0x0D
TTHL = 0x0E
TTHH = 0x0F
INT_OFFSET = 0x010
PIXEL_OFFSET = 0x80
// power modes
NORMAL_MODE = 0x00
SLEEP_MODE = 0x01
STAND_BY_60 = 0x20
STAND_BY_10 = 0x21
// resets
FLAG_RESET = 0x30
INITIAL_RESET = 0x3F
// frame rates
FPS_10 = 0x00
FPS_1 = 0x01
// interrupt modes
DIFFERENCE InterruptMode = 0x00
ABSOLUTE_VALUE InterruptMode = 0x01
PIXEL_TEMP_CONVERSION = 250
THERMISTOR_CONVERSION = 625
)
+98
View File
@@ -0,0 +1,98 @@
// Package apa102 implements a driver for the APA102 SPI LED.
//
// Datasheet: https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf
package apa102 // import "tinygo.org/x/drivers/apa102"
import (
"image/color"
"machine"
"tinygo.org/x/drivers"
)
const (
// BGR aka "Blue Green Red" is the current APA102 LED color order.
BGR = iota
// BRG aka "Blue Red Green" is the typical APA102 color order from 2015-2017.
BRG
// GRB aka "Green Red Blue" is the typical APA102 color order from pre-2015.
GRB
)
var startFrame = []byte{0x00, 0x00, 0x00, 0x00}
// Device wraps APA102 SPI LEDs.
type Device struct {
bus drivers.SPI
Order int
buf [4]byte
}
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
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, 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) {
d.startFrame()
// write data
for _, c := range cs {
// brightness is scaled to 5 bit value
d.buf[0] = 0xe0 | (c.A >> 3)
// set the colors
switch d.Order {
case BRG:
d.buf[1] = c.B
d.buf[2] = c.R
d.buf[3] = c.G
case GRB:
d.buf[1] = c.G
d.buf[2] = c.R
d.buf[3] = c.B
case BGR:
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))
return len(cs), nil
}
// Write the raw bytes using the APA102 protocol.
func (d *Device) Write(buf []byte) (n int, err error) {
d.startFrame()
d.bus.Tx(buf, nil)
d.endFrame(len(buf) / 4)
return len(buf), nil
}
// startFrame sends the start bytes for a strand of LEDs.
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) {
for i := 0; i < count/16; i++ {
d.bus.Transfer(0xff)
}
}
+70
View File
@@ -0,0 +1,70 @@
package apa102
import "machine"
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
// Note: making this unexported for now because it is probable not suitable
// most purposes other than the APA102 package. It might be desirable to make
// this more generic and include it in the TinyGo "machine" package instead.
type bbSPI struct {
SCK machine.Pin
SDO machine.Pin
Delay uint32
}
// 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.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
s.SCK.Low()
s.SDO.Low()
if s.Delay == 0 {
s.Delay = 1
}
}
// Tx matches signature of machine.SPI.Tx() and is used to send multiple bytes.
// The r slice is ignored and no error will ever be returned.
func (s *bbSPI) Tx(w []byte, r []byte) error {
s.Configure()
for _, b := range w {
s.Transfer(b)
}
return nil
}
// delay represents a quarter of the clock cycle
func (s *bbSPI) delay() {
for i := uint32(0); i < s.Delay; {
i++
}
}
// 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 SDO (MSB first)
if b&(1<<(7-i)) == 0 {
s.SDO.Low()
} else {
s.SDO.High()
}
s.delay()
// half clock cycle low
s.SCK.Low()
s.delay()
// for actual SPI would try to read the SDI value here
s.delay()
}
return 0, nil
}
+468
View File
@@ -0,0 +1,468 @@
// 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
}
// New creates a new APDS-9960 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
}
// Connected returns whether APDS-9960 has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := []byte{0}
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
return data[0] == 0xAB
}
// 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) configureDevice(cfg Configuration) {
d.DisableAll() // turn off everything
// "default" settings
if cfg.ProximityPulseLength == 0 {
cfg.ProximityPulseLength = 16
}
if cfg.ProximityPulseCount == 0 {
cfg.ProximityPulseCount = 64
}
if cfg.GesturePulseLength == 0 {
cfg.GesturePulseLength = 16
}
if cfg.GesturePulseCount == 0 {
cfg.GesturePulseCount = 64
}
if cfg.ProximityGain == 0 {
cfg.ProximityGain = 1
}
if cfg.GestureGain == 0 {
cfg.GestureGain = 1
}
if cfg.ColorGain == 0 {
cfg.ColorGain = 4
}
if cfg.ADCIntegrationCycles == 0 {
cfg.ADCIntegrationCycles = 4
}
if cfg.threshold == 0 {
d.gesture.threshold = 30
}
if cfg.sensitivity == 0 {
d.gesture.sensitivity = 20
}
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
if cfg.LEDBoost > 0 {
d.LEDBoost(cfg.LEDBoost)
}
}
func (d *Device) enable(cfg enableConfig) {
var gen, pien, aien, wen, pen, aen, pon uint8
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
}
}
+12
View File
@@ -0,0 +1,12 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package apds9960
import "tinygo.org/x/drivers"
// Configure sets up the APDS-9960 device.
func (d *Device) Configure(cfg Configuration) {
// configure device
d.configureDevice(cfg)
}
+24
View File
@@ -0,0 +1,24 @@
//go:build nano_33_ble
// +build nano_33_ble
package apds9960
import (
"machine"
"time"
)
// Configure sets up the APDS-9960 device.
func (d *Device) Configure(cfg Configuration) {
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
machine.LSM_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.LSM_PWR.High()
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.I2C_PULLUP.High()
// Wait a moment
time.Sleep(10 * time.Millisecond)
// configure device
d.configureDevice(cfg)
}
+78
View File
@@ -0,0 +1,78 @@
package apds9960
const (
// I2C address
ADPS9960_ADDRESS = 0x39
// control/status registers
APDS9960_RAM_REG = 0x00
APDS9960_ENABLE_REG = 0x80
APDS9960_ATIME_REG = 0x81
APDS9960_WTIME_REG = 0x83
APDS9960_AILTIL_REG = 0x84
APDS9960_AILTH_REG = 0x85
APDS9960_AIHTL_REG = 0x86
APDS9960_AIHTH_REG = 0x87
APDS9960_PILT_REG = 0x89
APDS9960_PIHT_REG = 0x8B
APDS9960_PERS_REG = 0x8C
APDS9960_CONFIG1_REG = 0x8D
APDS9960_PPULSE_REG = 0x8E
APDS9960_CONTROL_REG = 0x8F
APDS9960_CONFIG2_REG = 0x90
APDS9960_ID_REG = 0x92
APDS9960_STATUS_REG = 0x93
APDS9960_CDATAL_REG = 0x94
APDS9960_CDATAH_REG = 0x95
APDS9960_RDATAL_REG = 0x96
APDS9960_RDATAH_REG = 0x97
APDS9960_GDATAL_REG = 0x98
APDS9960_GDATAH_REG = 0x99
APDS9960_BDATAL_REG = 0x9A
APDS9960_BDATAH_REG = 0x9B
APDS9960_PDATA_REG = 0x9C
APDS9960_POFFSET_UR_REG = 0x9D
APDS9960_POFFSET_DL_REG = 0x9E
APDS9960_CONFIG3_REG = 0x9F
APDS9960_GPENTH_REG = 0xA0
APDS9960_GEXTH_REG = 0xA1
APDS9960_GCONF1_REG = 0xA2
APDS9960_GCONF2_REG = 0xA3
APDS9960_GOFFSET_U_REG = 0xA4
APDS9960_GOFFSET_D_REG = 0xA5
APDS9960_GOFFSET_L_REG = 0xA7
APDS9960_GOFFSET_R_REG = 0xA9
APDS9960_GPULSE_REG = 0xA6
APDS9960_GCONF3_REG = 0xAA
APDS9960_GCONF4_REG = 0xAB
APDS9960_GFLVL_REG = 0xAE
APDS9960_GSTATUS_REG = 0xAF
APDS9960_IFORCE_REG = 0xE4
APDS9960_PICLEAR_REG = 0xE5
APDS9960_CICLEAR_REG = 0xE6
APDS9960_AICLEAR_REG = 0xE7
APDS9960_GFIFO_U_REG = 0xFC
APDS9960_GFIFO_D_REG = 0xFD
APDS9960_GFIFO_L_REG = 0xFE
APDS9960_GFIFO_R_REG = 0xFF
)
const (
// sensor modes
MODE_NONE = iota
MODE_PROXIMITY
MODE_COLOR
MODE_GESTURE
)
const (
// detected gestures
GESTURE_NONE = iota
GESTURE_UP
GESTURE_DOWN
GESTURE_LEFT
GESTURE_RIGHT
)
+172
View File
@@ -0,0 +1,172 @@
// Package at24cx provides a driver for the AT24C32/64/128/256/512 2-wire serial EEPROM
//
// Datasheet:
// https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf
package at24cx // import "tinygo.org/x/drivers/at24cx"
import (
"errors"
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a DS3231 device.
type Device struct {
bus drivers.I2C
Address uint16
pageSize uint16
currentRAMAddress uint16
startRAMAddress uint16
endRAMAddress uint16
}
type Config struct {
PageSize uint16
StartRAMAddress uint16
EndRAMAddress uint16
}
// New creates a new AT24C32/64 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 sets up the device for communication
func (d *Device) Configure(cfg Config) {
if cfg.PageSize == 0 {
d.pageSize = 32
} else {
d.pageSize = cfg.PageSize
}
if cfg.EndRAMAddress == 0 {
d.endRAMAddress = 4096
} else {
d.endRAMAddress = cfg.EndRAMAddress
}
d.startRAMAddress = cfg.StartRAMAddress
}
// WriteByte writes a byte at the specified address
func (d *Device) WriteByte(eepromAddress uint16, value uint8) error {
address := []uint8{
uint8((eepromAddress >> 8) & 0xFF),
uint8(eepromAddress & 0xFF),
value,
}
return d.bus.Tx(d.Address, address, nil)
}
// ReadByte reads the byte at the specified address
func (d *Device) ReadByte(eepromAddress uint16) (uint8, error) {
address := []uint8{
uint8(eepromAddress >> 8),
uint8(eepromAddress & 0xFF),
}
data := make([]uint8, 1)
err := d.bus.Tx(d.Address, address, data)
return data[0], err
}
// WriteAt writes a byte array at the specified address
func (d *Device) WriteAt(data []byte, offset int64) (n int, err error) {
return d.writeAt(data, uint16(offset))
}
// writeAt writes a byte array at the specified address
func (d *Device) writeAt(data []byte, offset uint16) (n int, err error) {
values := make([]uint8, 32)
dataLeft := uint16(len(data))
d.currentRAMAddress = offset
offset = 0
var offsetPage uint16
var chunkLength uint16
for dataLeft > 0 {
offsetPage = d.currentRAMAddress % d.pageSize
if dataLeft < 30 { // The 32K/64K EEPROM is capable of 32-byte page writes and we're using 2 for the address
chunkLength = dataLeft
} else {
chunkLength = 30
}
if (d.pageSize - offsetPage) < chunkLength {
chunkLength = d.pageSize - offsetPage
}
for i := uint16(0); i < chunkLength; i++ {
values[2+i] = data[offset+i]
}
values[0] = uint8(d.currentRAMAddress >> 8)
values[1] = uint8(d.currentRAMAddress & 0xFF)
err := d.bus.Tx(d.Address, values[:chunkLength+2], nil)
if err != nil {
return 0, err
}
dataLeft -= chunkLength
offset += chunkLength
if d.endRAMAddress-chunkLength < d.currentRAMAddress {
d.currentRAMAddress = d.startRAMAddress + (d.currentRAMAddress+uint16(len(data)))%d.endRAMAddress
} else {
d.currentRAMAddress += chunkLength
}
time.Sleep(2 * time.Millisecond) // writing again too soon will block the device
}
return len(data), nil
}
// ReadAt reads the bytes at the specified address
func (d *Device) ReadAt(data []byte, offset int64) (n int, err error) {
return d.readAt(data, uint16(offset))
}
// readAt reads the bytes at the specified address
func (d *Device) readAt(data []byte, offset uint16) (n int, err error) {
address := []uint8{
uint8((offset >> 8) & 0xFF),
uint8(offset & 0xFF),
}
err = d.bus.Tx(d.Address, address, data)
if d.endRAMAddress-uint16(len(data)) < offset {
d.currentRAMAddress = d.startRAMAddress + (offset+uint16(len(data)))%d.endRAMAddress
} else {
d.currentRAMAddress = offset + uint16(len(data))
}
return len(data), err
}
// Seek sets the offset for the next Read or Write on SRAM to offset, interpreted
// according to whence: 0 means relative to the origin of the SRAM, 1 means
// relative to the current offset, and 2 means relative to the end.
// returns new offset and error, if any
func (d *Device) Seek(offset int64, whence int) (int64, error) {
w := uint16(0)
switch whence {
case 0:
w = d.startRAMAddress
case 1:
w = d.currentRAMAddress
case 2:
w = d.endRAMAddress
default:
return 0, errors.New("invalid whence")
}
d.currentRAMAddress = w + uint16(offset)
return int64(d.currentRAMAddress), nil
}
// Write writes len(data) bytes to SRAM
// returns number of bytes written and error, if any
func (d *Device) Write(data []byte) (n int, err error) {
return d.writeAt(data, d.currentRAMAddress)
}
// Read reads len(data) from SRAM
// returns number of bytes written and error, if any
func (d *Device) Read(data []uint8) (n int, err error) {
return d.readAt(data, d.currentRAMAddress)
}
+4
View File
@@ -0,0 +1,4 @@
package at24cx
// The I2C address which this device listens to.
const Address = 0x57
+258
View File
@@ -0,0 +1,258 @@
// Package axp192 provides a driver for the axp192 I2C Enhanced single Cell
// Li-Battery and Power System Management IC.
//
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
//
package axp192 // import "tinygo.org/x/drivers/axp192"
import (
"tinygo.org/x/drivers"
)
type Error uint8
const (
ErrInvalidID Error = 0x1
)
func (e Error) Error() string {
switch e {
case ErrInvalidID:
return "Invalid chip ID"
default:
return "Unknown error"
}
}
type Device struct {
bus drivers.I2C
buf []byte
Address uint8
}
// New returns AXP192 device for the provided I2C bus using default address.
func New(i2c drivers.I2C) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 2),
Address: Address,
}
}
type Config struct {
}
// Configure the AXP192 device.
func (d *Device) Configure(config Config) error {
return nil
}
// ReadPowerSupplyStatus reads power supply status.
func (d *Device) ReadPowerSupplyStatus() uint8 {
return d.read8bit(RegPowerSupplyStatus)
}
// SetVbusIPSOutAccessManagement sets VBUS-IPSOUT access management.
func (d *Device) SetVbusIPSOutAccessManagement(a uint8) {
d.write1Byte(RegVbusIPSOutAccessManagement, a)
}
// GetVbusIPSOutAccessManagement gets VBUS-IPSOUT access management.
func (d *Device) GetVbusIPSOutAccessManagement() uint8 {
return d.read8bit(RegVbusIPSOutAccessManagement)
}
// SetGPIO1Control sets GPIO1 function.
func (d *Device) SetGPIO1Control(a uint8) {
d.write1Byte(RegGPIO1Control, a)
}
// GetGPIO1Control gets GPIO1 function.
func (d *Device) GetGPIO1Control() uint8 {
return d.read8bit(RegGPIO1Control)
}
// SetGPIO2Control sets GPIO2 function.
func (d *Device) SetGPIO2Control(a uint8) {
d.write1Byte(RegGPIO2Control, a)
}
// GetGPIO2Control gets GPIO2 function.
func (d *Device) GetGPIO2Control() uint8 {
return d.read8bit(RegGPIO2Control)
}
// SetGPIO20SignalStatus sets GPIO[2:0] signal status.
func (d *Device) SetGPIO20SignalStatus(a uint8) {
d.write1Byte(RegGPIO20SignalStatus, a)
}
// GetGPIO20SignalStatus gets GPIO[2:0] signal status.
func (d *Device) GetGPIO20SignalStatus() uint8 {
return d.read8bit(RegGPIO20SignalStatus)
}
// SetBackupBatteryChargingControl sets backup battery charge control.
func (d *Device) SetBackupBatteryChargingControl(a uint8) {
d.write1Byte(RegBackupBatteryChargingControl, a)
}
// GetBackupBatteryChargingControl gets backup battery charge control.
func (d *Device) GetBackupBatteryChargingControl() uint8 {
return d.read8bit(RegBackupBatteryChargingControl)
}
// SetDCDC1VoltageSet sets DC-DC1 output voltage.
func (d *Device) SetDCDC1VoltageSet(a uint8) {
d.write1Byte(RegDCDC1VoltageSet, a)
}
// GetDCDC1VoltageSet gets DC-DC1 output voltage.
func (d *Device) GetDCDC1VoltageSet() uint8 {
return d.read8bit(RegDCDC1VoltageSet)
}
// SetDCDC2VoltageSet sets DC-DC2 dynamic voltage parameter.
func (d *Device) SetDCDC2VoltageSet(a uint8) {
d.write1Byte(RegDCDC2VoltageSet, a)
}
// GetDCDC2VoltageSet gets DC-DC2 dynamic voltage parameter.
func (d *Device) GetDCDC2VoltageSet() uint8 {
return d.read8bit(RegDCDC2VoltageSet)
}
// SetDCDC3VoltageSet sets DC-DC3 output voltage.
func (d *Device) SetDCDC3VoltageSet(a uint8) {
d.write1Byte(RegDCDC3VoltageSet, a)
}
// GetDCDC3VoltageSet gets DC-DC3 output voltage.
func (d *Device) GetDCDC3VoltageSet() uint8 {
return d.read8bit(RegDCDC3VoltageSet)
}
// SetLDO23VoltageSet sets LDO2/3 output voltage.
func (d *Device) SetLDO23VoltageSet(a uint8) {
d.write1Byte(RegLDO23VoltageSet, a)
}
// GetLDO23VoltageSet gets LDO2/3 output voltage.
func (d *Device) GetLDO23VoltageSet() uint8 {
return d.read8bit(RegLDO23VoltageSet)
}
// SetDCDC13LDO23Switch sets DC-DC1/3 & LOD2/3 output control.
func (d *Device) SetDCDC13LDO23Switch(a uint8) {
d.write1Byte(RegDCDC13LDO23Switch, a)
}
// GetDCDC13LDO23Switch gets DC-DC1/3 & LOD2/3 output control.
func (d *Device) GetDCDC13LDO23Switch() uint8 {
return d.read8bit(RegDCDC13LDO23Switch)
}
// SetGPIO43FunctionControl sets GPIO[4:3] pin function.
func (d *Device) SetGPIO43FunctionControl(a uint8) {
d.write1Byte(RegGPIO43FunctionControl, a)
}
// GetGPIO43FunctionControl gets GPIO[4:3] pin function.
func (d *Device) GetGPIO43FunctionControl() uint8 {
return d.read8bit(RegGPIO43FunctionControl)
}
// SetPEKParameterSet sets PEK press key parameter.
func (d *Device) SetPEKParameterSet(a uint8) {
d.write1Byte(RegPEKParameterSet, a)
}
// GetPEKParameterSet gets PEK press key parameter.
func (d *Device) GetPEKParameterSet() uint8 {
return d.read8bit(RegPEKParameterSet)
}
// SetADCEnableSet sets ADC enable 1.
func (d *Device) SetADCEnableSet(a uint8) {
d.write1Byte(RegADCEnableSet, a)
}
// GetADCEnableSet gets ADC enable 1.
func (d *Device) GetADCEnableSet() uint8 {
return d.read8bit(RegADCEnableSet)
}
// SetGPIO43SignalStatus sets GPIO[4:3] signal status.
func (d *Device) SetGPIO43SignalStatus(a uint8) {
d.write1Byte(RegGPIO43SignalStatus, a)
}
// GetGPIO43SignalStatus gets GPIO[4:3] signal status.
func (d *Device) GetGPIO43SignalStatus() uint8 {
return d.read8bit(RegGPIO43SignalStatus)
}
// SetDCVoltage sets DC voltage.
func (d *Device) SetDCVoltage(number uint8, voltage uint16) {
if voltage < 700 {
voltage = 0
} else {
voltage = (voltage - 700) / 25
}
switch number {
case 0:
v := d.GetDCDC1VoltageSet()
d.SetDCDC1VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
case 1:
v := d.GetDCDC2VoltageSet()
d.SetDCDC2VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
case 2:
v := d.GetDCDC3VoltageSet()
d.SetDCDC3VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
}
}
// SetLDOVoltage sets LDO voltage.
func (d *Device) SetLDOVoltage(number uint8, voltage uint16) {
if voltage > 3300 {
voltage = 15
} else {
voltage = (voltage / 100) - 18
}
switch number {
case 2:
v := d.GetLDO23VoltageSet()
d.SetLDO23VoltageSet((v & 0x0F) | (uint8(voltage) << 4))
break
case 3:
v := d.GetLDO23VoltageSet()
d.SetLDO23VoltageSet((v & 0xF0) | uint8(voltage))
break
}
}
// SetLDOEnable enable LDO.
func (d *Device) SetLDOEnable(number uint8, state bool) {
mark := uint8(0x01)
mark <<= number
switch number {
case 2:
v := d.GetDCDC13LDO23Switch()
d.SetDCDC13LDO23Switch(v | mark)
case 3:
v := d.GetDCDC13LDO23Switch()
d.SetDCDC13LDO23Switch(v & (^mark))
}
}
func (d *Device) write1Byte(reg, data uint8) {
d.bus.WriteRegister(d.Address, reg, []byte{data})
}
func (d *Device) read8bit(reg uint8) uint8 {
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
return d.buf[0]
}
+158
View File
@@ -0,0 +1,158 @@
package axp192
import (
"time"
"tinygo.org/x/drivers"
axp192orig "tinygo.org/x/drivers/axp192"
)
// Device wraps an I2C connection to a AXP192 device.
type Device struct {
*axp192orig.Device
LED Pin
RST Pin
SPK_EN Pin
}
// New creates a new AXP192 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(i2c drivers.I2C) *Device {
d := axp192orig.New(i2c)
axp := &Device{
Device: d,
}
axp.LED = Pin{pin: 1, axp: axp}
axp.SPK_EN = Pin{pin: 2, axp: axp}
axp.RST = Pin{pin: 4, axp: axp}
axp.begin()
return axp
}
type Config struct {
}
// Configure sets up the device for communication
func (d *Device) Configure(config Config) error {
return d.Device.Configure(axp192orig.Config{})
}
func (d *Device) begin() {
d.SetVbusIPSOutAccessManagement((d.GetVbusIPSOutAccessManagement() & 0x04) | 0x02)
d.SetGPIO1Control(d.GetGPIO1Control() & 0xF8)
d.SetGPIO2Control(d.GetGPIO2Control() & 0xF8)
d.SetBackupBatteryChargingControl((d.GetBackupBatteryChargingControl() & 0x1C) | 0xA2)
d.SetESPVoltage(3350)
d.SetLcdVoltage(3300)
d.SetLDOVoltage(2, 3300) //Periph power voltage preset (LCD_logic, SD card)
d.SetLDOVoltage(3, 2000) //Vibrator power voltage preset
d.SetLDOEnable(2, true)
d.SetDCDC3(true) // LCD Backlight
// GPIO4 : LCD Reset
d.SetGPIO43FunctionControl((d.GetGPIO43FunctionControl() & 0x72) | 0x84)
// Power On/Off Setting
d.SetPEKParameterSet(0x4C)
d.SetADCEnableSet(0xFF)
d.RST.Low()
time.Sleep(100 * time.Millisecond)
d.RST.High()
time.Sleep(100 * time.Millisecond)
}
// ToggleLED toggles LED connected to AXP192.
func (d *Device) ToggleLED() {
v := d.GetGPIO20SignalStatus()
if (v & 0x02) > 0 {
d.SetGPIO20SignalStatus(v & 0xFD)
} else {
d.SetGPIO20SignalStatus(v | 0x02)
}
}
// SetESPVoltage sets voltage of ESP32.
func (d *Device) SetESPVoltage(voltage uint16) {
if voltage >= 3000 && voltage <= 3400 {
d.SetDCVoltage(0, voltage)
}
}
// SetLcdVoltage sets voltage of LCD.
func (d *Device) SetLcdVoltage(voltage uint16) {
if voltage >= 2500 && voltage <= 3300 {
d.SetDCVoltage(2, voltage)
}
}
// SetDCDC3 enables or disables DCDC3.
func (d *Device) SetDCDC3(State bool) {
v := d.GetDCDC13LDO23Switch()
if State == true {
v = (1 << 1) | v
} else {
v = ^(uint8(1) << 1) & v
}
d.SetDCDC13LDO23Switch(v)
}
// Pin is a single pin on AXP192.
type Pin struct {
pin uint8
axp *Device
}
// High sets this GPIO pin to high.
func (p Pin) High() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
p.axp.SetGPIO20SignalStatus(v | 0x02)
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
v |= uint8(0x02)
p.axp.SetGPIO43SignalStatus(v)
}
}
// Low sets this GPIO pin to low.
func (p Pin) Low() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
p.axp.SetGPIO20SignalStatus(v & 0xFD)
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
v &= ^uint8(0x02)
p.axp.SetGPIO43SignalStatus(v)
}
}
// Toggle switches an output pin from low to high or from high to low.
func (p Pin) Toggle() {
switch p.pin {
case 1: // LED
v := p.axp.GetGPIO20SignalStatus()
if (v & 0x02) == 0 {
p.axp.SetGPIO20SignalStatus(v | 0x02)
} else {
p.axp.SetGPIO20SignalStatus(v & 0xFD)
}
case 2: // SPK_EN
case 4: // RST
v := p.axp.GetGPIO43SignalStatus()
if (v & 0x02) == 0 {
v |= uint8(0x02)
} else {
v &= ^uint8(0x02)
}
p.axp.SetGPIO43SignalStatus(v)
}
}
+127
View File
@@ -0,0 +1,127 @@
package axp192
// power supply control class
// 0x00 Power supply status register
// 0x01 Power supply mode/charging status register
// 0x04 OTG VBUS status register
// 0x0609 Data buffer register
// 0x10 EXTEN & DCDC2 switch register
// 0x12 DCDC1/3 & LDO2/3switch register
// 0x23 DCDC2 voltage set register
// 0x25 DCDC2 voltage slope set register
// 0x26 DCDC1voltage set register
// 0x27 DCDC3 voltage set register
// 0x28 LDO2/3 voltage set register
// 0x30 VBUSIPSOUT access set register
// 0x31 VOFF power off voltage set register
// 0x32 Power off、battery detect、CHGLED control register
// 0x33 Charging control register1
// 0x34 Charging control register2
// 0x35 Backup battery charging control register
// 0x36 PEK parameter set register
// 0x37 DCDC switch frequency set register
// 0x38 Battery charging under temperature warning set register
// 0x39 Battery charging over temperature warning set register
// 0x3A APS under voltage Level1 set register
// 0x3B APS under voltage Level2 set register
// 0x3C Battery discharging under temperature warning set register
// 0x3D Battery discharging over temperature warning set register
// 0x80 DCDC mode set register
// 0x82 ADC enable set register 1
// 0x83 ADC enable set register 2
// 0x84 ADC sample frequency set, TS pin control register
// 0x85 GPIO [3:0] input range set register
// 0x8A Timer control register
// 0x8B VBUS monitor set register
// 0x8F Over temperature power off control register
// GPIO control class
// 0x90 GPIO0 control register
// 0x91 GPIO0 LDO mode output voltage set register
// 0x92 GPIO1 control register
// 0x93 GPIO2 control register
// 0x94 GPIO[2:0] signal status register
// 0x95 GPIO[4:3] function control register
// 0x96 GPIO[4:3] signal status register
// 0x97 GPIO[2:0] pull down control register
// 0x98 PWM1 frequency set register
// 0x99 PWM1 duty ratio set register 1
// 0x9A PWM1 duty ratio set register 2
// 0x9B PWM2 frequency set register
// 0x9C PWM2 duty ratio set register 1
// 0x9D PWM2 duty ratio set register 2
// 0x9E GPIO5 control register
// IRQ control class
// 0x40 IRQ enable control register 1
// 0x41 IRQ enable control register 2
// 0x42 IRQ enable control register 3
// 0x43 IRQ enable control register 4
// 0x44 IRQ status register 1
// 0x45 IRQ status register 2
// 0x46 IRQ status register 3
// 0x47 IRQ status register 4
// ADC data class
// 0x56 ACIN voltage ADC data high 8 bit
// 0x57 ACIN voltage ADC data low 4 bit
// 0x58 ACIN current ADC data high 8 bit
// 0x59 ACIN current ADC data low 4 bit
// 0x5A VBUS voltage ADC data high 8 bit
// 0x5B VBUS voltage ADC data low 4 bit
// 0x5C VBUS current ADC data high 8 bit
// 0x5D VBUS current ADC data low 4 bit
// 0x5E AXP192 internal temperature monitor ADC data High 8 bit
// 0x5F AXP192 internal temperature monitor ADC data low 4 bit
// 0x62 TS input ADC data High 8 bitmonitor battery temperature by default
// 0x63 TS input ADC data low 4 bitmonitor battery temperature by default
// 0x64 GPIO0 voltage ADC data high 8 bit
// 0x65 GPIO0 voltage ADC data low 4 bit
// 0x66 GPIO1 voltage ADC data high 8 bit
// 0x67 GPIO1 voltage ADC data low 4 bit
// 0x68 GPIO2 voltage ADC data high 8 bit
// 0x69 GPIO2 voltage ADC data low 4 bit
// 0x6A GPIO[3] voltage ADC data high 8 bit
// 0x6B GPIO[3] voltage ADC data low 4 bit
// 0x70 Battery instantaneous power high 8 bit
// 0x71 Battery instantaneous power middle 8 bit
// 0x72 Battery instantaneous power low 8 bit
// 0x78 Battery voltage high 8 bit
// 0x79 Battery voltage low 4 bit
// 0x7A Battery charging current high 8 bit
// 0x7B Battery charging current low 5 bit
// 0x7C Battery discharging current high 8 bit
// 0x7D Battery discharging current low 5 bit
// 0x7E APS voltage high 8 bit
// 0x7F APS voltage low 4 bit
// 0xB0 Battery charging coulomb counter data register 3
// 0xB1 Battery charging coulomb counter data register 2
// 0xB2 Battery charging coulomb counter data register 1
// 0xB3 Battery charging coulomb counter data register 0
// 0xB4 Battery discharging coulomb counter data register 3
// 0xB5 Battery discharging coulomb counter data register 2
// 0xB6 Battery discharging coulomb counter data register 1
// 0xB7 Battery discharging coulomb counter data register 0
// 0xB8 Coulomb counter control register
const (
// Address is default I2C address.
Address = 0x34
RegPowerSupplyStatus = 0x00
RegDCDC13LDO23Switch = 0x12
RegVbusIPSOutAccessManagement = 0x30
RegBackupBatteryChargingControl = 0x35
RegDCDC2VoltageSet = 0x25
RegDCDC1VoltageSet = 0x26
RegDCDC3VoltageSet = 0x27
RegLDO23VoltageSet = 0x28
RegPEKParameterSet = 0x36
RegADCEnableSet = 0x82
RegGPIO1Control = 0x92
RegGPIO2Control = 0x93
RegGPIO20SignalStatus = 0x94
RegGPIO43FunctionControl = 0x95
RegGPIO43SignalStatus = 0x96
)
+72
View File
@@ -0,0 +1,72 @@
// Package bh1750 provides a driver for the BH1750 digital Ambient Light
//
// Datasheet:
// https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf
//
package bh1750 // import "tinygo.org/x/drivers/bh1750"
import (
"time"
"tinygo.org/x/drivers"
)
// SamplingMode is the sampling's resolution of the measurement
type SamplingMode byte
// Device wraps an I2C connection to a bh1750 device.
type Device struct {
bus drivers.I2C
Address uint16
mode SamplingMode
}
// New creates a new bh1750 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,
mode: CONTINUOUS_HIGH_RES_MODE,
}
}
// Configure sets up the device for communication
func (d *Device) Configure() {
d.bus.Tx(d.Address, []byte{POWER_ON}, nil)
d.SetMode(d.mode)
}
// RawSensorData returns the raw value from the bh1750
func (d *Device) RawSensorData() uint16 {
buf := []byte{1, 0}
d.bus.Tx(d.Address, nil, buf)
return (uint16(buf[0]) << 8) | uint16(buf[1])
}
// Illuminance returns the adjusted value in mlx (milliLux)
func (d *Device) Illuminance() int32 {
lux := uint32(d.RawSensorData())
var coef uint32
if d.mode == CONTINUOUS_HIGH_RES_MODE || d.mode == ONE_TIME_HIGH_RES_MODE {
coef = HIGH_RES
} else if d.mode == CONTINUOUS_HIGH_RES_MODE_2 || d.mode == ONE_TIME_HIGH_RES_MODE_2 {
coef = HIGH_RES2
} else {
coef = LOW_RES
}
// 100 * coef * lux * (5/6)
// 5/6 = measurement accuracy as per the datasheet
return int32(250 * coef * lux / 3)
}
// SetMode changes the reading mode for the sensor
func (d *Device) SetMode(mode SamplingMode) {
d.mode = mode
d.bus.Tx(d.Address, []byte{byte(d.mode)}, nil)
time.Sleep(10 * time.Millisecond)
}
+24
View File
@@ -0,0 +1,24 @@
package bh1750
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const Address = 0x23
// Registers. Names, addresses and comments copied from the datasheet.
const (
POWER_DOWN = 0x00
POWER_ON = 0x01
RESET = 0x07
CONTINUOUS_HIGH_RES_MODE SamplingMode = 0x10
CONTINUOUS_HIGH_RES_MODE_2 SamplingMode = 0x11
CONTINUOUS_LOW_RES_MODE SamplingMode = 0x13
ONE_TIME_HIGH_RES_MODE SamplingMode = 0x20
ONE_TIME_HIGH_RES_MODE_2 SamplingMode = 0x21
ONE_TIME_LOW_RES_MODE SamplingMode = 0x23
// resolution in 10*lx
HIGH_RES = 10
HIGH_RES2 = 5
LOW_RES = 40
)
+17 -12
View File
@@ -1,54 +1,59 @@
// Package blinkm implements a driver for the BlinkM I2C RGB LED.
//
// Datasheet: http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf
package blinkm
//
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
}
// New creates a new BlinkM connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus machine.I2C) Device {
return Device{bus}
func New(bus drivers.I2C) Device {
return Device{bus, Address}
}
// Configure sets up the device for communication
func (d *Device) Configure() {
d.bus.Tx(d.Address, []byte{'o'}, nil)
}
// Version returns the version of firmware on the BlinkM.
func (d Device) Version() (major, minor byte, err error) {
version := []byte{0, 0}
d.bus.ReadRegister(Address, GET_FIRMWARE, version)
d.bus.Tx(d.Address, []byte{GET_FIRMWARE}, version)
return version[0], version[1], nil
}
// SetRGB sets the RGB color on the BlinkM.
func (d Device) SetRGB(r, g, b byte) error {
d.bus.WriteRegister(Address, TO_RGB, []byte{r, g, b})
d.bus.Tx(d.Address, []byte{TO_RGB, r, g, b}, nil)
return nil
}
// GetRGB gets the current RGB color on the BlinkM.
func (d Device) GetRGB() (r, g, b byte, err error) {
color := []byte{0, 0, 0}
d.bus.ReadRegister(Address, GET_RGB, color)
d.bus.Tx(d.Address, []byte{GET_RGB}, color)
return color[0], color[1], color[2], nil
}
// FadeToRGB sets the RGB color on the BlinkM by fading from the current color
// to the new color.
func (d Device) FadeToRGB(r, g, b byte) error {
d.bus.WriteRegister(Address, FADE_TO_RGB, []byte{r, g, b})
d.bus.Tx(d.Address, []byte{FADE_TO_RGB, r, g, b}, nil)
return nil
}
// StopScript stops whatever script is currently running on the BlinkM.
func (d Device) StopScript() error {
d.bus.WriteRegister(Address, STOP_SCRIPT, nil)
d.bus.Tx(d.Address, []byte{STOP_SCRIPT}, nil)
return nil
}
+258
View File
@@ -0,0 +1,258 @@
// Package bme280 provides a driver for the BME280 digital combined
// humidity and pressure sensor by Bosch.
//
// Datasheet:
// https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
//
package bme280
import (
"math"
"tinygo.org/x/drivers"
)
// calibrationCoefficients reads at startup and stores the calibration coefficients
type calibrationCoefficients struct {
t1 uint16
t2 int16
t3 int16
p1 uint16
p2 int16
p3 int16
p4 int16
p5 int16
p6 int16
p7 int16
p8 int16
p9 int16
h1 uint8
h2 int16
h3 uint8
h4 int16
h5 int16
h6 int8
}
// Device wraps an I2C connection to a BME280 device.
type Device struct {
bus drivers.I2C
Address uint16
calibrationCoefficients calibrationCoefficients
}
// New creates a new BME280 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 sets up the device for communication and
// read the calibration coefficientes.
func (d *Device) Configure() {
var data [24]byte
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
if err != nil {
return
}
var h1 [1]byte
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H1, h1[:])
if err != nil {
return
}
var h2lsb [7]byte
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
if err != nil {
return
}
d.calibrationCoefficients.t1 = readUintLE(data[0], data[1])
d.calibrationCoefficients.t2 = readIntLE(data[2], data[3])
d.calibrationCoefficients.t3 = readIntLE(data[4], data[5])
d.calibrationCoefficients.p1 = readUintLE(data[6], data[7])
d.calibrationCoefficients.p2 = readIntLE(data[8], data[9])
d.calibrationCoefficients.p3 = readIntLE(data[10], data[11])
d.calibrationCoefficients.p4 = readIntLE(data[12], data[13])
d.calibrationCoefficients.p5 = readIntLE(data[14], data[15])
d.calibrationCoefficients.p6 = readIntLE(data[16], data[17])
d.calibrationCoefficients.p7 = readIntLE(data[18], data[19])
d.calibrationCoefficients.p8 = readIntLE(data[20], data[21])
d.calibrationCoefficients.p9 = readIntLE(data[22], data[23])
d.calibrationCoefficients.h1 = h1[0]
d.calibrationCoefficients.h2 = readIntLE(h2lsb[0], h2lsb[1])
d.calibrationCoefficients.h3 = h2lsb[2]
d.calibrationCoefficients.h6 = int8(h2lsb[6])
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{0x3f})
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{0xB7})
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{0x00})
}
// Connected returns whether a BME280 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(uint8(d.Address), WHO_AM_I, data)
return data[0] == CHIP_ID
}
// Reset the device
func (d *Device) Reset() {
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (int32, error) {
data, err := d.readData()
if err != nil {
return 0, err
}
temp, _ := d.calculateTemp(data)
return temp, nil
}
// ReadPressure returns the pressure in milli pascals mPa
func (d *Device) ReadPressure() (int32, error) {
data, err := d.readData()
if err != nil {
return 0, err
}
_, tFine := d.calculateTemp(data)
pressure := d.calculatePressure(data, tFine)
return pressure, nil
}
// ReadHumidity returns the relative humidity in hundredths of a percent
func (d *Device) ReadHumidity() (int32, error) {
data, err := d.readData()
if err != nil {
return 0, err
}
_, tFine := d.calculateTemp(data)
humidity := d.calculateHumidity(data, tFine)
return humidity, nil
}
// ReadAltitude returns the current altitude in meters based on the
// current barometric pressure and estimated pressure at sea level.
// Calculation is based on code from Adafruit BME280 library
// https://github.com/adafruit/Adafruit_BME280_Library
func (d *Device) ReadAltitude() (alt int32, err error) {
mPa, _ := d.ReadPressure()
atmP := float32(mPa) / 100000
alt = int32(44330.0 * (1.0 - math.Pow(float64(atmP/SEALEVEL_PRESSURE), 0.1903)))
return
}
// convert2Bytes converts two bytes to int32
func convert2Bytes(msb byte, lsb byte) int32 {
return int32(readUint(msb, lsb))
}
// 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))
}
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
func (d *Device) readData() (data [8]byte, err error) {
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
if err != nil {
println(err)
return
}
return
}
// calculateTemp uses the data slice and applies calibrations values on it to convert the value to milli degrees
// it also calculates the variable tFine which is used by the pressure and humidity calculation
func (d *Device) calculateTemp(data [8]byte) (int32, int32) {
rawTemp := convert3Bytes(data[3], data[4], data[5])
var1 := (((rawTemp >> 3) - (int32(d.calibrationCoefficients.t1) << 1)) * int32(d.calibrationCoefficients.t2)) >> 11
var2 := (((((rawTemp >> 4) - int32(d.calibrationCoefficients.t1)) * ((rawTemp >> 4) - int32(d.calibrationCoefficients.t1))) >> 12) * int32(d.calibrationCoefficients.t3)) >> 14
tFine := var1 + var2
T := (tFine*5 + 128) >> 8
return (10 * T), tFine
}
// calculatePressure uses the data slice and applies calibrations values on it to convert the value to milli pascals mPa
func (d *Device) calculatePressure(data [8]byte, tFine int32) int32 {
rawPressure := convert3Bytes(data[0], data[1], data[2])
var1 := int64(tFine) - 128000
var2 := var1 * var1 * int64(d.calibrationCoefficients.p6)
var2 = var2 + ((var1 * int64(d.calibrationCoefficients.p5)) << 17)
var2 = var2 + (int64(d.calibrationCoefficients.p4) << 35)
var1 = ((var1 * var1 * int64(d.calibrationCoefficients.p3)) >> 8) + ((var1 * int64(d.calibrationCoefficients.p2)) << 12)
var1 = ((int64(1) << 47) + var1) * int64(d.calibrationCoefficients.p1) >> 33
if var1 == 0 {
return 0 // avoid exception caused by division by zero
}
p := int64(1048576 - rawPressure)
p = (((p << 31) - var2) * 3125) / var1
var1 = (int64(d.calibrationCoefficients.p9) * (p >> 13) * (p >> 13)) >> 25
var2 = (int64(d.calibrationCoefficients.p8) * p) >> 19
p = ((p + var1 + var2) >> 8) + (int64(d.calibrationCoefficients.p7) << 4)
p = (p / 256)
return int32(1000 * p)
}
// calculateHumidity uses the data slice and applies calibrations values on it to convert the value to relative humidity in hundredths of a percent
func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
rawHumidity := convert2Bytes(data[6], data[7])
h := float32(tFine) - 76800
if h == 0 {
println("invalid value")
}
var1 := float32(rawHumidity) - (float32(d.calibrationCoefficients.h4)*64.0 +
(float32(d.calibrationCoefficients.h5) / 16384.0 * h))
var2 := float32(d.calibrationCoefficients.h2) / 65536.0 *
(1.0 + float32(d.calibrationCoefficients.h6)/67108864.0*h*
(1.0+float32(d.calibrationCoefficients.h3)/67108864.0*h))
h = var1 * var2
h = h * (1 - float32(d.calibrationCoefficients.h1)*h/524288)
return int32(100 * h)
}
+25
View File
@@ -0,0 +1,25 @@
package bme280
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const Address = 0x76
// Registers. Names, addresses and comments copied from the datasheet.
const (
CTRL_MEAS_ADDR = 0xF4
CTRL_HUMIDITY_ADDR = 0xF2
CTRL_CONFIG = 0xF5
REG_PRESSURE = 0xF7
REG_CALIBRATION = 0x88
REG_CALIBRATION_H1 = 0xA1
REG_CALIBRATION_H2LSB = 0xE1
CMD_RESET = 0xE0
WHO_AM_I = 0xD0
CHIP_ID = 0x60
)
const (
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
)
+223
View File
@@ -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()
}
+44
View File
@@ -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
)
+183
View File
@@ -0,0 +1,183 @@
// Package bmp180 provides a driver for the BMP180 digital pressure sensor
// by Bosch.
//
// Datasheet:
// https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
//
package bmp180 // import "tinygo.org/x/drivers/bmp180"
import (
"time"
"tinygo.org/x/drivers"
)
// OversamplingMode is the oversampling ratio of the pressure measurement.
type OversamplingMode uint
// calibrationCoefficients reads at startup and stores the calibration coefficients
type calibrationCoefficients struct {
ac1 int16
ac2 int16
ac3 int16
ac4 uint16
ac5 uint16
ac6 uint16
b1 int16
b2 int16
mb int16
mc int16
md int16
}
// Device wraps an I2C connection to a BMP180 device.
type Device struct {
bus drivers.I2C
Address uint16
mode OversamplingMode
calibrationCoefficients calibrationCoefficients
}
// New creates a new BMP180 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,
mode: ULTRAHIGHRESOLUTION,
}
}
// Connected returns whether a BMP180 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(uint8(d.Address), WHO_AM_I, data)
return data[0] == CHIP_ID
}
// Configure sets up the device for communication and
// read the calibration coefficients.
func (d *Device) Configure() {
data := make([]byte, 22)
err := d.bus.ReadRegister(uint8(d.Address), AC1_MSB, data)
if err != nil {
return
}
d.calibrationCoefficients.ac1 = readInt(data[0], data[1])
d.calibrationCoefficients.ac2 = readInt(data[2], data[3])
d.calibrationCoefficients.ac3 = readInt(data[4], data[5])
d.calibrationCoefficients.ac4 = readUint(data[6], data[7])
d.calibrationCoefficients.ac5 = readUint(data[8], data[9])
d.calibrationCoefficients.ac6 = readUint(data[10], data[11])
d.calibrationCoefficients.b1 = readInt(data[12], data[13])
d.calibrationCoefficients.b2 = readInt(data[14], data[15])
d.calibrationCoefficients.mb = readInt(data[16], data[17])
d.calibrationCoefficients.mc = readInt(data[18], data[19])
d.calibrationCoefficients.md = readInt(data[20], data[21])
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *Device) ReadTemperature() (temperature int32, err error) {
rawTemp, err := d.rawTemp()
if err != nil {
return
}
b5 := d.calculateB5(rawTemp)
t := (b5 + 8) >> 4
return 100 * t, nil
}
// ReadPressure returns the pressure in milli pascals (mPa).
func (d *Device) ReadPressure() (pressure int32, err error) {
rawTemp, err := d.rawTemp()
if err != nil {
return
}
rawPressure, err := d.rawPressure(d.mode)
if err != nil {
return
}
b5 := d.calculateB5(rawTemp)
b6 := b5 - 4000
x1 := (int32(d.calibrationCoefficients.b2) * (b6 * b6 >> 12)) >> 11
x2 := (int32(d.calibrationCoefficients.ac2) * b6) >> 11
x3 := x1 + x2
b3 := (((int32(d.calibrationCoefficients.ac1)*4 + x3) << uint(d.mode)) + 2) >> 2
x1 = (int32(d.calibrationCoefficients.ac3) * b6) >> 13
x2 = (int32(d.calibrationCoefficients.b1) * ((b6 * b6) >> 12)) >> 16
x3 = ((x1 + x2) + 2) >> 2
b4 := (uint32(d.calibrationCoefficients.ac4) * uint32(x3+32768)) >> 15
b7 := uint32(rawPressure-b3) * (50000 >> uint(d.mode))
var p int32
if b7 < 0x80000000 {
p = int32((b7 << 1) / b4)
} else {
p = int32((b7 / b4) << 1)
}
x1 = (p >> 8) * (p >> 8)
x1 = (x1 * 3038) >> 16
x2 = (-7357 * p) >> 16
return 1000 * (p + ((x1 + x2 + 3791) >> 4)), nil
}
// rawTemp returns the sensor's raw values of the temperature
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)
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP_MSB, data)
if err != nil {
return 0, err
}
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 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
}
// rawPressure returns the sensor's raw values of the pressure
func (d *Device) rawPressure(mode OversamplingMode) (int32, error) {
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)})
time.Sleep(pauseForReading(mode))
data := make([]byte, 3)
err := d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE_MSB, data)
if err != nil {
return 0, err
}
rawPressure := int32((uint32(data[0])<<16 + uint32(data[1])<<8 + uint32(data[2])) >> (8 - uint(mode)))
return rawPressure, nil
}
// pauseForReading returns the pause duration depending on the sampling mode
func pauseForReading(mode OversamplingMode) time.Duration {
var d time.Duration
switch mode {
case ULTRALOWPOWER:
d = 5 * time.Millisecond
case STANDARD:
d = 8 * time.Millisecond
case HIGHRESOLUTION:
d = 14 * time.Millisecond
case ULTRAHIGHRESOLUTION:
d = 26 * time.Millisecond
}
return d
}
// readInt converts two bytes to int16
func readInt(msb byte, lsb byte) int16 {
return int16(uint16(msb)<<8 | uint16(lsb))
}
// readUint converts two bytes to uint16
func readUint(msb byte, lsb byte) uint16 {
return (uint16(msb) << 8) | uint16(lsb)
}
+30
View File
@@ -0,0 +1,30 @@
package bmp180
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const Address = 0x77
// Registers. Names, addresses and comments copied from the datasheet.
const (
AC1_MSB = 0xAA // Calibration coefficients start at 0xAA ends at 0xBF
CMD_TEMP = 0x2E
CMD_PRESSURE = 0x34
REG_CTRL = 0xF4
REG_TEMP_MSB = 0xF6
REG_PRESSURE_MSB = 0xF6
WHO_AM_I = 0xD0
CHIP_ID = 0x55
)
const (
// ULTRALOWPOWER is the lowest oversampling mode of the pressure measurement.
ULTRALOWPOWER OversamplingMode = iota
// BSTANDARD is the standard oversampling mode of the pressure measurement.
STANDARD
// HIGHRESOLUTION is a high oversampling mode of the pressure measurement.
HIGHRESOLUTION
// ULTRAHIGHRESOLUTION is the highest oversampling mode of the pressure measurement.
ULTRAHIGHRESOLUTION
)
+244
View File
@@ -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))
}
+56
View File
@@ -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
)
+249
View File
@@ -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})
}
+84
View File
@@ -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
)
+71
View File
@@ -0,0 +1,71 @@
// Package buzzer provides a very simplistic driver for a connected buzzer or low-fidelity speaker.
//
package buzzer // import "tinygo.org/x/drivers/buzzer"
import (
"machine"
"time"
)
// Device wraps a GPIO connection to a buzzer.
type Device struct {
pin machine.Pin
High bool
BPM float64
}
// New returns a new buzzer driver given which pin to use
func New(pin machine.Pin) Device {
return Device{
pin: pin,
High: false,
BPM: 96.0,
}
}
// On sets the buzzer to a high state.
func (l *Device) On() (err error) {
l.pin.Set(true)
l.High = true
return
}
// Off sets the buzzer to a low state.
func (l *Device) Off() (err error) {
l.pin.Set(false)
l.High = false
return
}
// Toggle sets the buzzer to the opposite of it's current state
func (l *Device) Toggle() (err error) {
if l.High {
err = l.Off()
} else {
err = l.On()
}
return
}
// Tone plays a tone of the requested frequency and duration.
func (l *Device) Tone(hz, duration float64) (err error) {
// calculation based off https://www.arduino.cc/en/Tutorial/Melody
tone := (1.0 / (2.0 * hz)) * 1000000.0
tempo := ((60 / l.BPM) * (duration * 1000))
for i := 0.0; i < tempo*1000; i += tone * 2.0 {
if err = l.On(); err != nil {
return
}
time.Sleep(time.Duration(tone) * time.Microsecond)
if err = l.Off(); err != nil {
return
}
time.Sleep(time.Duration(tone) * time.Microsecond)
}
return
}
+121
View File
@@ -0,0 +1,121 @@
package buzzer
const (
Whole = 4
Half = 2
Quarter = 1
Eighth = 0.500
)
// The values seem like they are little off, so feel free to make corrections, as needed.
const (
Rest = 0
C0 = 16.35
Db0 = 17.32
D0 = 18.35
Eb0 = 19.45
E0 = 20.60
F0 = 21.83
Gb0 = 23.12
G0 = 24.50
Ab0 = 25.96
A0 = 27.50
Bb0 = 29.14
B0 = 30.87
C1 = 32.70
Db1 = 34.65
D1 = 36.71
Eb1 = 38.89
E1 = 41.20
F1 = 43.65
Gb1 = 46.25
G1 = 49.00
Ab1 = 51.91
A1 = 55.00
Bb1 = 58.27
B1 = 61.74
C2 = 65.41
Db2 = 69.30
D2 = 73.42
Eb2 = 77.78
E2 = 82.41
F2 = 87.31
Gb2 = 92.50
G2 = 98.00
Ab2 = 103.83
A2 = 110.00
Bb2 = 116.54
B2 = 123.47
C3 = 130.81
Db3 = 138.59
D3 = 146.83
Eb3 = 155.56
E3 = 164.81
F3 = 174.61
Gb3 = 185.00
G3 = 196.00
Ab3 = 207.65
A3 = 220.00
Bb3 = 233.08
B3 = 246.94
C4 = 261.63
Db4 = 277.18
D4 = 293.66
Eb4 = 311.13
E4 = 329.63
F4 = 349.23
Gb4 = 369.99
G4 = 392.00
Ab4 = 415.30
A4 = 440.00
Bb4 = 466.16
B4 = 493.88
C5 = 523.25
Db5 = 554.37
D5 = 587.33
Eb5 = 622.25
E5 = 659.25
F5 = 698.46
Gb5 = 739.99
G5 = 783.99
Ab5 = 830.61
A5 = 880.00
Bb5 = 932.33
B5 = 987.77
C6 = 1046.50
Db6 = 1108.73
D6 = 1174.66
Eb6 = 1244.51
E6 = 1318.51
F6 = 1396.91
Gb6 = 1479.98
G6 = 1567.98
Ab6 = 1661.22
A6 = 1760.00
Bb6 = 1864.66
B6 = 1975.53
C7 = 2093.00
Db7 = 2217.46
D7 = 2349.32
Eb7 = 2489.02
E7 = 2637.02
F7 = 2793.83
Gb7 = 2959.96
G7 = 3135.96
Ab7 = 3322.44
A7 = 3520.00
Bb7 = 3729.31
B7 = 3951.07
C8 = 4186.01
Db8 = 4434.92
D8 = 4698.63
Eb8 = 4978.03
E8 = 5274.04
F8 = 5587.65
Gb8 = 5919.91
G8 = 6271.93
Ab8 = 6644.88
A8 = 7040.00
Bb8 = 7458.62
B8 = 7902.13
)
+49
View File
@@ -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
}
+116
View File
@@ -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)
}
+7
View File
@@ -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
+7
View File
@@ -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
+218
View File
@@ -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,
}
}
+154
View File
@@ -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
View File
@@ -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)
}
+14
View File
@@ -0,0 +1,14 @@
package drivers
import "image/color"
type Displayer interface {
// Size returns the current size of the display.
Size() (x, y int16)
// SetPizel modifies the internal buffer.
SetPixel(x, y int16, c color.RGBA)
// Display sends the buffer (if any) to the screen.
Display() error
}
+42 -4
View File
@@ -1,4 +1,42 @@
// Package drivers is just a placeholder for the sub-packages.
// It is here just to be able to install the package without errors using
// go get -d github.com/ayke/tinygo-drivers
package drivers
// Package drivers provides a collection of hardware drivers for TinyGo (https://tinygo.org)
// for devices such as sensors and displays.
//
// Here is an example in TinyGo that uses the BMP180 digital barometer:
//
// package main
//
// import (
// "time"
// "machine"
//
// "tinygo.org/x/drivers/bmp180"
// )
//
// func main() {
// machine.I2C0.Configure(machine.I2CConfig{})
// sensor := bmp180.New(machine.I2C0)
// sensor.Configure()
//
// connected := sensor.Connected()
// if !connected {
// println("BMP180 not detected")
// return
// }
// println("BMP180 detected")
//
// for {
// temp, _ := sensor.ReadTemperature()
// println("Temperature:", float32(temp)/1000, "°C")
//
// pressure, _ := sensor.ReadPressure()
// println("Pressure", float32(pressure)/100000, "hPa")
//
// time.Sleep(2 * time.Second)
// }
// }
//
// Each individual driver is contained within its own sub-package within this package and
// there are no interdependencies in order to minimize the final size of compiled code that
// uses any of these drivers.
//
package drivers // import "tinygo.org/x/drivers"
+173
View File
@@ -0,0 +1,173 @@
// Package ds1307 provides a driver for the DS1307 RTC
//
// Datasheet:
// https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
//
package ds1307 // import "tinygo.org/x/drivers/ds1307"
import (
"errors"
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a DS1307 device.
type Device struct {
bus drivers.I2C
Address uint8
AddressSRAM uint8
}
// New creates a new DS1307 connection. I2C bus must be already configured.
func New(bus drivers.I2C) Device {
return Device{bus: bus,
Address: uint8(I2CAddress),
AddressSRAM: SRAMBeginAddres,
}
}
// SetTime sets the time and date
func (d *Device) SetTime(t time.Time) error {
data := make([]byte, 8)
data[0] = uint8(TimeDate)
data[1] = decToBcd(t.Second())
data[2] = decToBcd(t.Minute())
data[3] = decToBcd(t.Hour())
data[4] = decToBcd(int(t.Weekday() + 1))
data[5] = decToBcd(t.Day())
data[6] = decToBcd(int(t.Month()))
data[7] = decToBcd(t.Year() - 2000)
err := d.bus.Tx(uint16(d.Address), data, nil)
return err
}
// 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 {
return time.Time{}, err
}
seconds := bcdToDec(data[0] & 0x7F)
minute := bcdToDec(data[1])
hour := hoursBCDToInt(data[2])
day := bcdToDec(data[4])
month := time.Month(bcdToDec(data[5]))
year := bcdToDec(data[6])
year += 2000
t := time.Date(year, month, day, hour, minute, seconds, 0, time.UTC)
return t, nil
}
// Seek sets the offset for the next Read or Write on SRAM to offset, interpreted
// according to whence: 0 means relative to the origin of the SRAM, 1 means
// relative to the current offset, and 2 means relative to the end.
// returns new offset and error, if any
func (d *Device) Seek(offset int64, whence int) (int64, error) {
switch whence {
case 0:
whence = SRAMBeginAddres
case 1:
whence = int(d.AddressSRAM)
case 2:
whence = SRAMEndAddress
default:
return 0, errors.New("invalid starting point")
}
d.AddressSRAM = uint8(whence) + uint8(offset)
if d.AddressSRAM > SRAMEndAddress {
return 0, errors.New("EOF")
}
return int64(d.AddressSRAM), nil
}
// Write writes len(data) bytes to SRAM
// returns number of bytes written and error, if any
func (d *Device) Write(data []byte) (n int, err error) {
if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
return 0, errors.New("writing outside of SRAM")
}
buffer := make([]byte, len(data)+1)
buffer[0] = d.AddressSRAM
copy(buffer[1:], data)
err = d.bus.Tx(uint16(d.Address), buffer, nil)
if err != nil {
return 0, err
}
d.Seek(int64(len(data)), 1)
return len(data), nil
}
// Read reads len(data) from SRAM
// returns number of bytes written and error, if any
func (d *Device) Read(data []uint8) (n int, err error) {
if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
return 0, errors.New("EOF")
}
err = d.bus.ReadRegister(d.Address, d.AddressSRAM, data)
if err != nil {
return 0, err
}
d.Seek(int64(len(data)), 1)
return len(data), nil
}
// SetOscillatorFrequency sets output oscillator frequency
// Available modes: SQW_OFF, SQW_1HZ, SQW_4KHZ, SQW_8KHZ, SQW_32KHZ
func (d *Device) SetOscillatorFrequency(sqw uint8) error {
data := []byte{uint8(Control), sqw}
err := d.bus.Tx(uint16(d.Address), data, nil)
return err
}
// IsOscillatorRunning returns if the oscillator is running
func (d *Device) IsOscillatorRunning() bool {
data := []byte{0}
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
if err != nil {
return false
}
return (data[0] & (1 << CH)) == 0
}
// SetOscillatorRunning starts/stops internal oscillator by toggling halt bit
func (d *Device) SetOscillatorRunning(running bool) error {
data := make([]byte, 3)
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
if err != nil {
return err
}
if running {
data[0] &^= (1 << CH)
} else {
data[0] |= (1 << CH)
}
data[1], data[0] = data[0], uint8(TimeDate)
err = d.bus.Tx(uint16(d.Address), data[:2], nil)
return err
}
// decToBcd converts int to BCD
func decToBcd(dec int) uint8 {
return uint8(dec + 6*(dec/10))
}
// bcdToDec converts BCD to int
func bcdToDec(bcd uint8) int {
return int(bcd - 6*(bcd>>4))
}
// hoursBCDToInt converts the BCD hours to int
func hoursBCDToInt(value uint8) (hour int) {
if value&0x40 != 0x00 {
hour = bcdToDec(value & 0x1F)
if (value & 0x20) != 0x00 {
hour += 12
}
} else {
hour = bcdToDec(value)
}
return
}
+19
View File
@@ -0,0 +1,19 @@
package ds1307
const (
I2CAddress = 0x68
TimeDate = 0x00
Control = 0x7
//CH is oscillator halt bit
CH = 0x7
SRAMBeginAddres = 0x8
SRAMEndAddress = 0x3F
)
const (
SQW_OFF = 0x0
SQW_1HZ = 0x10
SQW_4KHZ = 0x11
SQW_8KHZ = 0x12
SQW_32KHZ = 0x13
)
+167
View File
@@ -0,0 +1,167 @@
// Package ds3231 provides a driver for the DS3231 RTC
//
// Datasheet:
// https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
package ds3231 // import "tinygo.org/x/drivers/ds3231"
import (
"time"
"tinygo.org/x/drivers"
)
type Mode uint8
// Device wraps an I2C connection to a DS3231 device.
type Device struct {
bus drivers.I2C
Address uint16
}
// New creates a new DS3231 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 sets up the device for communication
func (d *Device) Configure() bool {
return true
}
// IsTimeValid return true/false is the time in the device is valid
func (d *Device) IsTimeValid() bool {
data := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
if err != nil {
return false
}
return (data[0] & (1 << OSF)) == 0x00
}
// IsRunning returns if the oscillator is running
func (d *Device) IsRunning() bool {
data := []uint8{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
if err != nil {
return false
}
return (data[0] & (1 << EOSC)) == 0x00
}
// SetRunning starts the internal oscillator
func (d *Device) SetRunning(isRunning bool) error {
data := []uint8{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
if isRunning {
data[0] &^= uint8(1 << EOSC)
} else {
data[0] |= 1 << EOSC
}
err = d.bus.WriteRegister(uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
return nil
}
// SetTime sets the date and time in the DS3231
func (d *Device) SetTime(dt time.Time) error {
data := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data[0] &^= 1 << OSF
err = d.bus.WriteRegister(uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data = make([]uint8, 7)
data[0] = uint8ToBCD(uint8(dt.Second()))
data[1] = uint8ToBCD(uint8(dt.Minute()))
data[2] = uint8ToBCD(uint8(dt.Hour()))
year := uint8(dt.Year() - 2000)
centuryFlag := uint8(0)
if year >= 100 {
year -= 100
centuryFlag = 1 << 7
}
data[3] = uint8ToBCD(uint8(dt.Weekday()))
data[4] = uint8ToBCD(uint8(dt.Day()))
data[5] = uint8ToBCD(uint8(dt.Month()) | centuryFlag)
data[6] = uint8ToBCD(year)
err = d.bus.WriteRegister(uint8(d.Address), REG_TIMEDATE, data)
if err != nil {
return err
}
return nil
}
// ReadTime returns the date and time
func (d *Device) ReadTime() (dt time.Time, err error) {
data := make([]uint8, 7)
err = d.bus.ReadRegister(uint8(d.Address), REG_TIMEDATE, data)
if err != nil {
return
}
second := bcdToInt(data[0] & 0x7F)
minute := bcdToInt(data[1])
hour := hoursBCDToInt(data[2])
day := bcdToInt(data[4])
monthRaw := data[5]
year := bcdToInt(data[6]) + 2000
if monthRaw&(1<<7) != 0x00 {
year += 100
}
month := time.Month(bcdToInt(monthRaw & 0x7F))
dt = time.Date(year, month, day, hour, minute, second, 0, time.UTC)
return
}
// ReadTemperature returns the temperature in millicelsius (mC)
func (d *Device) ReadTemperature() (int32, error) {
data := make([]uint8, 2)
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP, data)
if err != nil {
return 0, err
}
return int32(data[0])*1000 + int32((data[1]>>6)*25)*10, nil
}
// uint8ToBCD converts a byte to BCD for the DS3231
func uint8ToBCD(value uint8) uint8 {
return value + 6*(value/10)
}
// bcdToInt converts BCD from the DS3231 to int
func bcdToInt(value uint8) int {
return int(value - 6*(value>>4))
}
// hoursBCDToInt converts the BCD hours to int
func hoursBCDToInt(value uint8) (hour int) {
if value&0x40 != 0x00 {
hour = bcdToInt(value & 0x1F)
if (value & 0x20) != 0x00 {
hour += 12
}
} else {
hour = bcdToInt(value)
}
return
}
+48
View File
@@ -0,0 +1,48 @@
package ds3231
// The I2C address which this device listens to.
const Address = 0x68
// Registers
const (
REG_TIMEDATE = 0x00
REG_ALARMONE = 0x07
REG_ALARMTWO = 0x0B
REG_CONTROL = 0x0E
REG_STATUS = 0x0F
REG_AGING = 0x10
REG_TEMP = 0x11
REG_ALARMONE_SIZE = 4
REG_ALARMTWO_SIZE = 3
// DS3231 Control Register Bits
A1IE = 0
A2IE = 1
INTCN = 2
RS1 = 3
RS2 = 4
CONV = 5
BBSQW = 6
EOSC = 7
// DS3231 Status Register Bits
A1F = 0
A2F = 1
BSY = 2
EN32KHZ = 3
OSF = 7
AlarmFlag_Alarm1 = 0x01
AlarmFlag_Alarm2 = 0x02
AlarmFlag_AlarmBoth = 0x03
None Mode = 0
BatteryBackup Mode = 1
Clock Mode = 2
AlarmOne Mode = 3
AlarmTwo Mode = 4
ModeAlarmBoth Mode = 5
)
+160
View File
@@ -0,0 +1,160 @@
// Package easystepper provides a simple driver to rotate a 4-wire stepper motor.
package easystepper // import "tinygo.org/x/drivers/easystepper"
import (
"machine"
"time"
)
// Device holds the pins and the delay between steps
type Device struct {
pins [4]machine.Pin
stepDelay int32
stepNumber uint8
}
// DualDevice holds information for controlling 2 motors
type DualDevice struct {
devices [2]Device
}
// New returns a new easystepper driver given 4 pins, number of steps and rpm
func New(pin1, pin2, pin3, pin4 machine.Pin, steps int32, rpm int32) Device {
return Device{
pins: [4]machine.Pin{pin1, pin2, pin3, pin4},
stepDelay: 60000000 / (steps * rpm),
}
}
// Configure configures the pins of the Device
func (d *Device) Configure() {
for _, pin := range d.pins {
pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
}
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
func NewDual(pin1, pin2, pin3, pin4, pin5, pin6, pin7, pin8 machine.Pin, steps int32, rpm int32) DualDevice {
var dual DualDevice
dual.devices[0] = Device{
pins: [4]machine.Pin{pin1, pin2, pin3, pin4},
stepDelay: 60000000 / (steps * rpm),
}
dual.devices[1] = Device{
pins: [4]machine.Pin{pin5, pin6, pin7, pin8},
stepDelay: 60000000 / (steps * rpm),
}
return dual
}
// Configure configures the pins of the DualDevice
func (d *DualDevice) Configure() {
d.devices[0].Configure()
d.devices[1].Configure()
}
// Move rotates the motor the number of given steps
// (negative steps will rotate it the opposite direction)
func (d *Device) Move(steps int32) {
direction := steps > 0
if steps < 0 {
steps = -steps
}
steps += int32(d.stepNumber)
var s int32
d.stepMotor(d.stepNumber)
for s = int32(d.stepNumber); s < steps; s++ {
time.Sleep(time.Duration(d.stepDelay) * time.Microsecond)
d.moveDirectionSteps(direction, s)
}
}
// Off turns off all motor pins
func (d *Device) Off() {
for _, pin := range d.pins {
pin.Low()
}
}
// Move rotates the motors the number of given steps
// (negative steps will rotate it the opposite direction)
func (d *DualDevice) Move(stepsA, stepsB int32) {
min := uint8(1)
max := uint8(0)
var directions [2]bool
var minStep int32
directions[0] = stepsA > 0
directions[1] = stepsB > 0
if stepsA < 0 {
stepsA = -stepsA
}
if stepsB < 0 {
stepsB = -stepsB
}
if stepsB > stepsA {
stepsA, stepsB = stepsB, stepsA
max, min = min, max
}
d.devices[0].stepMotor(d.devices[0].stepNumber)
d.devices[1].stepMotor(d.devices[1].stepNumber)
stepsA += int32(d.devices[max].stepNumber)
minStep = int32(d.devices[min].stepNumber)
for s := int32(d.devices[max].stepNumber); s < stepsA; s++ {
time.Sleep(time.Duration(d.devices[0].stepDelay) * time.Microsecond)
d.devices[max].moveDirectionSteps(directions[max], s)
if ((s * stepsB) / stepsA) > minStep {
minStep++
d.devices[min].moveDirectionSteps(directions[min], minStep)
}
}
}
// Off turns off all motor pins
func (d *DualDevice) Off() {
d.devices[0].Off()
d.devices[1].Off()
}
// stepMotor changes the pins' state to the correct step
func (d *Device) stepMotor(step uint8) {
switch step {
case 0:
d.pins[0].High()
d.pins[1].Low()
d.pins[2].High()
d.pins[3].Low()
break
case 1:
d.pins[0].Low()
d.pins[1].High()
d.pins[2].High()
d.pins[3].Low()
break
case 2:
d.pins[0].Low()
d.pins[1].High()
d.pins[2].Low()
d.pins[3].High()
break
case 3:
d.pins[0].High()
d.pins[1].Low()
d.pins[2].Low()
d.pins[3].High()
break
}
d.stepNumber = step
}
// moveDirectionSteps uses the direction to calculate the correct step and change the motor to it.
// Direction true: 0, 1, 2, 3, 0, 1, 2, ...
// Direction false: 0, 3, 2, 1, 0, 3, 2, ...
func (d *Device) moveDirectionSteps(direction bool, step int32) {
if direction {
d.stepMotor(uint8(step % 4))
} else {
d.stepMotor(uint8((step + 2*(step%2)) % 4))
}
}
+84
View File
@@ -0,0 +1,84 @@
# ESP-AT Driver
This package provides a driver to use a separate connected WiFi processor either the ESP8266 or the ESP32 from Espressif.
The way this driver works is by using the UART interface to communicate with the WiFi chip using the Espressif AT command set.
## ESP-AT Firmware Installation
In order to use this driver, you must have the ESP-AT firmware installed on the ESP8266/ESP32 chip.
### Installing on Arduino Nano33 IoT
In order to install the needed firmware on the Arduino Nano33 IoT board's built-in NINA W102 chip, you will need to use the `arduino-nano33-iot` branch of this fork of the firmware:
https://github.com/hybridgroup/esp32-at
To flash this firmware on the Arduino Nano33 IoT you will need to follow the following procedure:
- Install _Arduino SAMD Boards_ from the Boards Manager.
- Install _WiFiNANO_ from the Library Manager.
- Using the normal Arduino software, load the `SerialNINAPassthrough` sketch on to the board (in File -> Examples -> WiFiNINA-> Tools).
- Flash the NINA 102 firmware using the `make flash` command in the https://github.com/hybridgroup/esp32-at repo.
You only need to do this one time, and then the correct ESP-AT firmware will be on the NINA chip, and you can just flash the Arduino Nano33 IoT board using TinyGo. We should be able to remove some of these step in a future release of this software.
### Installing on ESP32
The official repository for the ESP-AT for the ESP32 processor is located here:
https://github.com/espressif/esp32-at
Your best option is to follow the instructions in the official repo.
### Installing on ESP8266
The official repository for the AT command set firmware for the ESP8266 processor is located here:
https://github.com/espressif/ESP8266_NONOS_SDK
First clone the repo:
```shell
git clone https://github.com/espressif/ESP8266_NONOS_SDK.git
```
You will also need to install the Espressif `esptool` to flash this firmware on your ESP8266:
https://github.com/espressif/esptool
Once you have obtained the binary code, and installed `esptool`, you can flash the ESP8266.
Here is an example shell script that flashes a Wemos D1 Mini board:
```python
#!/bin/sh
SPToolDir="$HOME/.local/lib/python2.7/site-packages"
FirmwareDir="$HOME/Development/ESP8266_NONOS_SDK"
cd "$SPToolDir"
port=/dev/ttyUSB0
if [ ! -c $port ]; then
port=/dev/ttyUSB0
fi
if [ ! -c $port ]; then
echo "No device appears to be plugged in. Stopping."
fi
printf "Writing AT firmware to the Wemos D1 Mini in 3..."
sleep 1; printf "2..."
sleep 1; printf "1..."
sleep 1; echo "done."
echo "Erasing the flash first"
esptool.py --port $port erase_flash
esptool.py --port /dev/ttyUSB0 --baud 115200 \
write_flash -fm dio -ff 20m -fs detect \
0x0000 "$FirmwareDir/bin/boot_v1.7.bin" \
0x01000 "$FirmwareDir/bin/at/512+512/user1.1024.new.2.bin" \
0x3fc000 "$FirmwareDir/bin/esp_init_data_default_v05.bin" \
0x7e000 "$FirmwareDir/bin/blank.bin" \
0x3fe000 "$FirmwareDir/bin/blank.bin"
echo "Check the boot by typing: miniterm $port 74800"
echo " and then resetting. Use Ctrl-] to quit miniterm."
```
+20
View File
@@ -0,0 +1,20 @@
package espat
import (
"time"
"tinygo.org/x/drivers/net"
)
func (d *Device) ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error {
if len(ssid) == 0 {
return net.ErrWiFiMissingSSID
}
d.SetWifiMode(WifiModeClient)
return d.ConnectToAP(ssid, pass, 10)
}
func (d *Device) Disconnect() error {
return d.DisconnectFromAP()
}
+111
View File
@@ -0,0 +1,111 @@
package espat
// Basic AT commands
const (
// Test that the device is working.
Test = ""
// Restart module
Restart = "+RST"
// Version show info about the current software version.
Version = "+GMR"
// Enter deep-sleep mode
Sleep = "+GSLP"
// Configure echo.
EchoConfig = "E"
// EchoConfigOn
EchoConfigOn = EchoConfig + "1"
// EchoConfigOff
EchoConfigOff = EchoConfig + "0"
// Configure UART
UARTConfig = "+UART"
)
// WiFi commands.
const (
// WiFi mode (sta/AP/sta+AP)
WifiMode = "+CWMODE"
// Connect to an access point.
ConnectAP = "+CWJAP"
// List available AP's
ListAP = "+CWLAP"
// Disconnect from the current AP
Disconnect = "+CWQAP"
// Set softAP configuration. This also activates the ESP8266/ESP32 to act as an access point.
// On the ESP8266 the settings will not be saved in flash memory, so they will be forgotten on next reset.
// On the ESP32 the settings WILL be saved in flash memory, so they will be used on next reset.
SoftAPConfigCurrent = "+CWSAP"
// Set softAP configuration. This also activates the ESP8266/ESP32 to act as an access point.
// On the ESP8266 the settings will not be saved in flash memory, so they will be forgotten on next reset.
// On the ESP32 the settings WILL be saved in flash memory, so they will be used on next reset.
SoftAPConfigFlash = "+CWSAP"
// List station IP's connected to softAP
ListConnectedIP = "+CWLIF"
// Enable/disable DHCP
DHCPConfig = "+CWDHCP"
// Set MAC address of station
SetStationMACAddress = "+CIPSTAMAC"
// Set MAC address of softAP
SetAPMACAddress = "+CIPAPMAC"
// Set IP address of ESP8266/ESP32 station
SetStationIP = "+CIPSTA"
// Set IP address of ESP8266/ESP32 when acting as access point.
// On the ESP8266 the IP address will not be saved in flash memory, so it will be forgotten on next reset.
// On the ESP32 the IP address WILL be saved in flash memory, so it will be used on next reset.
SetSoftAPIPCurrent = "+CIPAP"
// Set IP address of ESP8266/ESP32 when acting as access point.
// On the ESP8266 the IP address will not be saved in flash memory, so it will be forgotten on next reset.
// On the ESP32 the IP address WILL be saved in flash memory, so it will be used on next reset.
SetSoftAPIPFlash = "+CIPAP"
)
// TCP/IP commands
const (
// Get connection status
TCPStatus = "+CIPSTATUS"
// Establish TCP connection or register UDP port
TCPConnect = "+CIPSTART"
// DNS Lookup
TCPDNSLookup = "+CIPDOMAIN"
// Send Data
TCPSend = "+CIPSEND"
// Close TCP/UDP connection
TCPClose = "+CIPCLOSE"
// Get local IP address
GetLocalIP = "+CIFSR"
// Set multiple connections mode
TCPMultiple = "+CIPMUX"
// Configure as server
ServerConfig = "+CIPSERVER"
// Set transmission mode
TransmissionMode = "+CIPMODE"
// Set timeout when ESP8266/ESP32 runs as TCP server
SetServerTimeout = "+CIPSTO"
)
+222
View File
@@ -0,0 +1,222 @@
// Package espat implements TCP/UDP wireless communication over serial
// with a separate ESP8266 or ESP32 board using the Espressif AT command set
// across a UART interface.
//
// In order to use this driver, the ESP8266/ESP32 must be flashed with firmware
// supporting the AT command set. Many ESP8266/ESP32 chips already have this firmware
// installed by default. You will need to install this firmware if you have an
// ESP8266 that has been flashed with NodeMCU (Lua) or Arduino firmware.
//
// AT Command Core repository:
// https://github.com/espressif/esp32-at
//
// Datasheet:
// https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf
//
// AT command set:
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
//
package espat // import "tinygo.org/x/drivers/espat"
import (
"errors"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/net"
)
// Device wraps UART connection to the ESP8266/ESP32.
type Device struct {
bus drivers.UART
// command responses that come back from the ESP8266/ESP32
response []byte
// data received from a TCP/UDP connection forwarded by the ESP8266/ESP32
socketdata []byte
}
// ActiveDevice is the currently configured Device in use. There can only be one.
var ActiveDevice *Device
// New returns a new espat driver. Pass in a fully configured UART bus.
func New(b drivers.UART) *Device {
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
}
// Configure sets up the device for communication.
func (d Device) Configure() {
ActiveDevice = &d
net.ActiveDevice = ActiveDevice
}
// Connected checks if there is communication with the ESP8266/ESP32.
func (d *Device) Connected() bool {
d.Execute(Test)
// handle response here, should include "OK"
_, err := d.Response(100)
if err != nil {
return false
}
return true
}
// Write raw bytes to the UART.
func (d *Device) Write(b []byte) (n int, err error) {
return d.bus.Write(b)
}
// Read raw bytes from the UART.
func (d *Device) Read(b []byte) (n int, err error) {
return d.bus.Read(b)
}
// how long in milliseconds to pause after sending AT commands
const pause = 300
// Execute sends an AT command to the ESP8266/ESP32.
func (d Device) Execute(cmd string) error {
_, err := d.Write([]byte("AT" + cmd + "\r\n"))
return err
}
// Query sends an AT command to the ESP8266/ESP32 that returns the
// current value for some configuration parameter.
func (d Device) Query(cmd string) (string, error) {
_, err := d.Write([]byte("AT" + cmd + "?\r\n"))
return "", err
}
// Set sends an AT command with params to the ESP8266/ESP32 for a
// configuration value to be set.
func (d Device) Set(cmd, params string) error {
_, err := d.Write([]byte("AT" + cmd + "=" + params + "\r\n"))
return err
}
// Version returns the ESP8266/ESP32 firmware version info.
func (d Device) Version() []byte {
d.Execute(Version)
r, err := d.Response(100)
if err != nil {
return []byte("unknown")
}
return r
}
// Echo sets the ESP8266/ESP32 echo setting.
func (d Device) Echo(set bool) {
if set {
d.Execute(EchoConfigOn)
} else {
d.Execute(EchoConfigOff)
}
// TODO: check for success
d.Response(100)
}
// Reset restarts the ESP8266/ESP32 firmware. Due to how the baud rate changes,
// this messes up communication with the ESP8266/ESP32 module. So make sure you know
// what you are doing when you call this.
func (d Device) Reset() {
d.Execute(Restart)
d.Response(100)
}
// ReadSocket returns the data that has already been read in from the responses.
func (d *Device) ReadSocket(b []byte) (n int, err error) {
// make sure no data in buffer
d.Response(300)
count := len(b)
if len(b) >= len(d.socketdata) {
// copy it all, then clear socket data
count = len(d.socketdata)
copy(b, d.socketdata[:count])
d.socketdata = d.socketdata[:0]
} else {
// copy all we can, then keep the remaining socket data around
copy(b, d.socketdata[:count])
copy(d.socketdata, d.socketdata[count:])
d.socketdata = d.socketdata[:len(d.socketdata)-count]
}
return count, nil
}
// Response gets the next response bytes from the ESP8266/ESP32.
// The call will retry for up to timeout milliseconds before returning nothing.
func (d *Device) Response(timeout int) ([]byte, error) {
// read data
var size int
var start, end int
pause := 100 // pause to wait for 100 ms
retries := timeout / pause
for {
size = d.bus.Buffered()
if size > 0 {
end += size
d.bus.Read(d.response[start:end])
// if "+IPD" then read socket data
if strings.Contains(string(d.response[:end]), "+IPD") {
// handle socket data
return nil, d.parseIPD(end)
}
// if "OK" then the command worked
if strings.Contains(string(d.response[:end]), "OK") {
return d.response[start:end], nil
}
// if "Error" then the command failed
if strings.Contains(string(d.response[:end]), "ERROR") {
return d.response[start:end], errors.New("response error:" + string(d.response[start:end]))
}
// if anything else, then keep reading data in?
start = end
}
// wait longer?
retries--
if retries == 0 {
return nil, errors.New("response timeout error:" + string(d.response[start:end]))
}
time.Sleep(time.Duration(pause) * time.Millisecond)
}
}
func (d *Device) parseIPD(end int) error {
// find the "+IPD," to get length
s := strings.Index(string(d.response[:end]), "+IPD,")
// find the ":"
e := strings.Index(string(d.response[:end]), ":")
// find the data length
val := string(d.response[s+5 : e])
// TODO: verify count
_, err := strconv.Atoi(val)
if err != nil {
// not expected data here. what to do?
return err
}
// load up the socket data
d.socketdata = append(d.socketdata, d.response[e+1:end]...)
return nil
}
// IsSocketDataAvailable returns of there is socket data available
func (d *Device) IsSocketDataAvailable() bool {
return len(d.socketdata) > 0 || d.bus.Buffered() > 0
}
+147
View File
@@ -0,0 +1,147 @@
package espat
import (
"errors"
"strconv"
"strings"
)
const (
TCPMuxSingle = 0
TCPMuxMultiple = 1
TCPTransferModeNormal = 0
TCPTransferModeUnvarnished = 1
)
// GetDNS returns the IP address for a domain name.
func (d *Device) GetDNS(domain string) (string, error) {
d.Set(TCPDNSLookup, "\""+domain+"\"")
resp, err := d.Response(1000)
if err != nil {
return "", err
}
if !strings.Contains(string(resp), ":") {
return "", errors.New("GetDNS error:" + string(resp))
}
r := strings.Split(string(resp), ":")
if len(r) != 2 {
return "", errors.New("Invalid domain lookup result")
}
res := strings.Split(r[1], "\r\n")
return res[0], nil
}
// ConnectTCPSocket creates a new TCP socket connection for the ESP8266/ESP32.
// Currently only supports single connection mode.
func (d *Device) ConnectTCPSocket(addr, port string) error {
protocol := "TCP"
val := "\"" + protocol + "\",\"" + addr + "\"," + port + ",120"
err := d.Set(TCPConnect, val)
if err != nil {
return err
}
_, e := d.Response(3000)
if e != nil {
return e
}
return nil
}
// ConnectUDPSocket creates a new UDP connection for the ESP8266/ESP32.
func (d *Device) ConnectUDPSocket(addr, sendport, listenport string) error {
protocol := "UDP"
val := "\"" + protocol + "\",\"" + addr + "\"," + sendport + "," + listenport + ",2"
err := d.Set(TCPConnect, val)
if err != nil {
return err
}
_, e := d.Response(3000)
if e != nil {
return e
}
return nil
}
// ConnectSSLSocket creates a new SSL socket connection for the ESP8266/ESP32.
// Currently only supports single connection mode.
func (d *Device) ConnectSSLSocket(addr, port string) error {
protocol := "SSL"
val := "\"" + protocol + "\",\"" + addr + "\"," + port + ",120"
d.Set(TCPConnect, val)
// this operation takes longer, so wait up to 6 seconds to complete.
_, err := d.Response(6000)
if err != nil {
return err
}
return nil
}
// DisconnectSocket disconnects the ESP8266/ESP32 from the current TCP/UDP connection.
func (d *Device) DisconnectSocket() error {
err := d.Execute(TCPClose)
if err != nil {
return err
}
_, e := d.Response(pause)
if e != nil {
return e
}
return nil
}
// SetMux sets the ESP8266/ESP32 current client TCP/UDP configuration for concurrent connections
// either single TCPMuxSingle or multiple TCPMuxMultiple (up to 4).
func (d *Device) SetMux(mode int) error {
val := strconv.Itoa(mode)
d.Set(TCPMultiple, val)
_, err := d.Response(pause)
return err
}
// GetMux returns the ESP8266/ESP32 current client TCP/UDP configuration for concurrent connections.
func (d *Device) GetMux() ([]byte, error) {
d.Query(TCPMultiple)
return d.Response(pause)
}
// SetTCPTransferMode sets the ESP8266/ESP32 current client TCP/UDP transfer mode.
// Either TCPTransferModeNormal or TCPTransferModeUnvarnished.
func (d *Device) SetTCPTransferMode(mode int) error {
val := strconv.Itoa(mode)
d.Set(TransmissionMode, val)
_, err := d.Response(pause)
return err
}
// GetTCPTransferMode returns the ESP8266/ESP32 current client TCP/UDP transfer mode.
func (d *Device) GetTCPTransferMode() ([]byte, error) {
d.Query(TransmissionMode)
return d.Response(pause)
}
// StartSocketSend gets the ESP8266/ESP32 ready to receive TCP/UDP socket data.
func (d *Device) StartSocketSend(size int) error {
val := strconv.Itoa(size)
d.Set(TCPSend, val)
// when ">" is received, it indicates
// ready to receive data
r, err := d.Response(2000)
if err != nil {
return err
}
if strings.Contains(string(r), ">") {
return nil
}
return errors.New("StartSocketSend error:" + string(r))
}
// EndSocketSend tell the ESP8266/ESP32 the TCP/UDP socket data sending is complete,
// and to return to command mode. This is only used in "unvarnished" raw mode.
func (d *Device) EndSocketSend() error {
d.Write([]byte("+++"))
_, err := d.Response(pause)
return err
}
+154
View File
@@ -0,0 +1,154 @@
package espat
import (
"strconv"
)
const (
WifiModeClient = 1
WifiModeAP = 2
WifiModeDual = 3
WifiAPSecurityOpen = 1
WifiAPSecurityWPA_PSK = 2
WifiAPSecurityWPA2_PSK = 3
WifiAPSecurityWPA_WPA2_PSK = 4
)
// GetWifiMode returns the ESP8266/ESP32 wifi mode.
func (d *Device) GetWifiMode() ([]byte, error) {
d.Query(WifiMode)
return d.Response(100)
}
// SetWifiMode sets the ESP8266/ESP32 wifi mode.
func (d *Device) SetWifiMode(mode int) error {
val := strconv.Itoa(mode)
d.Set(WifiMode, val)
_, err := d.Response(pause)
return err
}
// Wifi Client
// GetConnectedAP returns the ESP8266/ESP32 is currently connected to as a client.
func (d *Device) GetConnectedAP() ([]byte, error) {
d.Query(ConnectAP)
return d.Response(100)
}
// ConnectToAP connects the ESP8266/ESP32 to an access point.
// ws is the number of seconds to wait for connection.
func (d *Device) ConnectToAP(ssid, pwd string, ws int) error {
val := "\"" + ssid + "\",\"" + pwd + "\""
d.Set(ConnectAP, val)
_, err := d.Response(ws * 1000)
if err != nil {
return err
}
return nil
}
// DisconnectFromAP disconnects the ESP8266/ESP32 from the current access point.
func (d *Device) DisconnectFromAP() error {
d.Execute(Disconnect)
_, err := d.Response(1000)
return err
}
// GetClientIP returns the ESP8266/ESP32 current client IP addess when connected to an Access Point.
func (d *Device) GetClientIP() (string, error) {
d.Query(SetStationIP)
r, err := d.Response(1000)
return string(r), err
}
// SetClientIP sets the ESP8266/ESP32 current client IP addess when connected to an Access Point.
func (d *Device) SetClientIP(ipaddr string) error {
val := "\"" + ipaddr + "\""
d.Set(ConnectAP, val)
_, err := d.Response(500)
return err
}
// Access Point
// GetAPConfig returns the ESP8266/ESP32 current configuration when acting as an Access Point.
func (d *Device) GetAPConfig() (string, error) {
d.Query(SoftAPConfigCurrent)
r, err := d.Response(100)
return string(r), err
}
// SetAPConfig sets the ESP8266/ESP32 current configuration when acting as an Access Point.
// ch indicates which radiochannel to use. security should be one of the const values
// such as WifiAPSecurityOpen etc.
func (d *Device) SetAPConfig(ssid, pwd string, ch, security int) error {
chval := strconv.Itoa(ch)
ecnval := strconv.Itoa(security)
val := "\"" + ssid + "\",\"" + pwd + "\"," + chval + "," + ecnval
d.Set(SoftAPConfigCurrent, val)
_, err := d.Response(1000)
return err
}
// GetAPClients returns the ESP8266/ESP32 current clients when acting as an Access Point.
func (d *Device) GetAPClients() (string, error) {
d.Query(ListConnectedIP)
r, err := d.Response(100)
return string(r), err
}
// GetAPIP returns the ESP8266/ESP32 current IP addess when configured as an Access Point.
func (d *Device) GetAPIP() (string, error) {
d.Query(SetSoftAPIPCurrent)
r, err := d.Response(100)
return string(r), err
}
// SetAPIP sets the ESP8266/ESP32 current IP addess when configured as an Access Point.
func (d *Device) SetAPIP(ipaddr string) error {
val := "\"" + ipaddr + "\""
d.Set(SetSoftAPIPCurrent, val)
_, err := d.Response(500)
return err
}
// GetAPConfigFlash returns the ESP8266/ESP32 current configuration acting as an Access Point
// from flash storage. These settings are those used after a reset.
func (d *Device) GetAPConfigFlash() (string, error) {
d.Query(SoftAPConfigFlash)
r, err := d.Response(100)
return string(r), err
}
// SetAPConfigFlash sets the ESP8266/ESP32 current configuration acting as an Access Point,
// and saves them to flash storage. These settings will be used after a reset.
// ch indicates which radiochannel to use. security should be one of the const values
// such as WifiAPSecurityOpen etc.
func (d *Device) SetAPConfigFlash(ssid, pwd string, ch, security int) error {
chval := strconv.Itoa(ch)
ecnval := strconv.Itoa(security)
val := "\"" + ssid + "\",\"" + pwd + "\"," + chval + "," + ecnval
d.Set(SoftAPConfigFlash, val)
_, err := d.Response(1000)
return err
}
// GetAPIPFlash returns the ESP8266/ESP32 IP address as saved to flash storage.
// This is the IP address that will be used after a reset.
func (d *Device) GetAPIPFlash() (string, error) {
d.Query(SetSoftAPIPFlash)
r, err := d.Response(100)
return string(r), err
}
// SetAPIPFlash sets the ESP8266/ESP32 current IP addess when configured as an Access Point.
// The IP will be saved to flash storage, and will be used after a reset.
func (d *Device) SetAPIPFlash(ipaddr string) error {
val := "\"" + ipaddr + "\""
d.Set(SetSoftAPIPFlash, val)
_, err := d.Response(500)
return err
}
+27
View File
@@ -0,0 +1,27 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/adt7410"
)
var (
i2c = machine.I2C0
sensor = adt7410.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
sensor.Configure()
for {
temp := sensor.ReadTempF()
fmt.Printf("temperature: %f\r\n", temp)
time.Sleep(time.Second)
}
}
+25
View File
@@ -0,0 +1,25 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/adxl345"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := adxl345.New(machine.I2C0)
sensor.Configure()
println("ADXL345 starts")
for {
x, y, z, _ := sensor.ReadAcceleration()
println("X:", x, "Y:", y, "Z:", z)
rx, ry, rz := sensor.ReadRawAcceleration()
println("X (raw):", rx, "Y (raw):", ry, "Z (raw):", rz)
time.Sleep(100 * time.Millisecond)
}
}
+55
View File
@@ -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)
}
File diff suppressed because one or more lines are too long
+56
View File
@@ -0,0 +1,56 @@
package main
import (
"image/color"
"machine"
"tinygo.org/x/drivers/st7735"
"tinygo.org/x/drivers/amg88xx"
)
func main() {
machine.SPI1.Configure(machine.SPIConfig{
SCK: machine.SPI1_SCK_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})
display := st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE)
display.Configure(st7735.Config{
Rotation: st7735.ROTATION_90,
})
display.FillScreen(color.RGBA{0, 0, 0, 255})
camera := amg88xx.New(machine.I2C0)
camera.Configure(amg88xx.Config{})
var data [64]int16
var value int16
for {
// get the values of the sensor in millicelsius
camera.ReadPixels(&data)
for j := int16(0); j < 8; j++ {
for i := int16(0); i < 8; i++ {
value = data[63-(i+j*8)]
// treat anything below 18°C as 18°C
if value < 18000 {
value = 0
} else {
value = (value - 18000) / 36
// our color array only have 433 values, avoid getting a value that doesn't exist
if value > 432 {
value = 432
}
}
// show the image on the PyBadge's display
display.FillRectangle(16+i*16, j*16, 16, 16, colors[value])
}
}
}
}
+91
View File
@@ -0,0 +1,91 @@
// This example demostrates how to control the "Dotstar" (APA102) LED included
// on the Adafruit Itsy Bitsy M0 board. It implements a "rainbow effect" based
// on the following example:
// https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/master/CircuitPython_Essentials/CircuitPython_Internal_RGB_LED_rainbow.py
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/apa102"
)
var (
apa *apa102.Device
pwm = machine.TCC0
leds = make([]color.RGBA, 1)
wheel = &Wheel{Brightness: 0x10}
)
func init() {
// APA102 on Itsy Bitsy is connected to pins that require a software-based
// SPI implementation.
apa = apa102.NewSoftwareSPI(machine.PA00, machine.PA01, 1)
// Configure the regular on-board LED for PWM fading
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
// with the scheduler disabled.
go func() {
for i, brightening := uint8(0), false; ; i++ {
if i == 0 {
brightening = !brightening
continue
}
var brightness uint32 = uint32(i)
if !brightening {
brightness = 256 - brightness
}
pwm.Set(channelLED, pwm.Top()*brightness/256)
time.Sleep(5 * time.Millisecond)
}
}()
// Use the "wheel" function from Adafruit's example to cycle the APA102
for {
leds[0] = wheel.Next()
apa.WriteColors(leds)
time.Sleep(25 * time.Millisecond)
}
}
// Wheel is a port of Adafruit's Circuit Python example referenced above.
type Wheel struct {
Brightness uint8
pos uint8
}
// Next increments the internal state of the color and returns the new RGBA
func (w *Wheel) Next() (c color.RGBA) {
pos := w.pos
if w.pos < 85 {
c = color.RGBA{R: 0xFF - pos*3, G: pos * 3, B: 0x0, A: w.Brightness}
} else if w.pos < 170 {
pos -= 85
c = color.RGBA{R: 0x0, G: 0xFF - pos*3, B: pos * 3, A: w.Brightness}
} else {
pos -= 170
c = color.RGBA{R: pos * 3, G: 0x0, B: 0xFF - pos*3, A: w.Brightness}
}
w.pos++
return
}
+35
View File
@@ -0,0 +1,35 @@
// Connects to an APA102 SPI RGB LED strip with 30 LEDS.
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/apa102"
)
func main() {
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 500000,
Mode: 0})
a := apa102.New(machine.SPI0)
leds := make([]color.RGBA, 30)
rg := false
for {
rg = !rg
for i := range leds {
rg = !rg
if rg {
leds[i] = color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0x77}
} else {
leds[i] = color.RGBA{R: 0x00, G: 0xff, B: 0x00, A: 0x77}
}
}
a.WriteColors(leds)
time.Sleep(100 * time.Millisecond)
}
}
+39
View File
@@ -0,0 +1,39 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
// use Nano 33 BLE Sense's internal I2C bus
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.SCL1_PIN,
SDA: machine.SDA1_PIN,
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
sensor.Configure(apds9960.Configuration{}) // use default settings
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.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)
}
}
+52
View File
@@ -0,0 +1,52 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
// use Nano 33 BLE Sense's internal I2C bus
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.SCL1_PIN,
SDA: machine.SDA1_PIN,
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
sensor.Configure(apds9960.Configuration{}) // use default settings
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.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: // the nRF52 chip is "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)
}
}
+40
View File
@@ -0,0 +1,40 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9960"
)
func main() {
// use Nano 33 BLE Sense's internal I2C bus
machine.I2C1.Configure(machine.I2CConfig{
SCL: machine.SCL1_PIN,
SDA: machine.SDA1_PIN,
Frequency: machine.TWI_FREQ_400KHZ,
})
sensor := apds9960.New(machine.I2C1)
// use default settings
sensor.Configure(apds9960.Configuration{})
if !sensor.Connected() {
println("APDS-9960 not connected!")
return
}
sensor.EnableProximity() // enable proximity engine
for {
if sensor.ProximityAvailable() {
p := sensor.ReadProximity()
println("Proximity:", p)
}
time.Sleep(time.Millisecond * 100)
}
}
+122
View File
@@ -0,0 +1,122 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/at24cx"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
eeprom := at24cx.New(machine.I2C0)
eeprom.Configure(at24cx.Config{})
values := make([]uint8, 100)
for i := uint16(0); i < 100; i++ {
values[i] = uint8(65 + i%26)
}
_, err := eeprom.WriteAt(values, 0)
if err != nil {
println("There was an error in WriteAt:", err)
return
}
for i := uint16(0); i < 26; i++ {
err = eeprom.WriteByte(100+i, uint8(90-i))
if err != nil {
println("There was an error in WriteByte:", i, err)
return
}
time.Sleep(2 * time.Millisecond)
}
println("\n\r\n\rRead 26 bytes one by one from address 0")
println("Expected: ABCDEFGHIJKLMNOPQRSTUVWXYZ")
print("Real: ")
for i := uint16(0); i < 26; i++ {
char, err := eeprom.ReadByte(i)
print(string(char))
if err != nil {
println("There was an error in ReadByte:", i, err)
return
}
}
println("")
println("\n\r\n\rRead 100 bytes from address 26")
println("Expected: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVZYXWVUTSRQPONMLKJIHGFEDCBA")
print("Real: ")
data := make([]byte, 100)
_, err = eeprom.ReadAt(data, 26)
if err != nil {
println("There was an error in ReadAt:", err)
return
}
for i := 0; i < 100; i++ {
print(string(data[i]))
}
println("")
// Move to the beginning of memory
eeprom.Seek(0, 0)
_, err = eeprom.Write([]uint8{88, 88, 88})
if err != nil {
println("There was an error in Write:", err)
return
}
println("\n\r\n\rRead 3 bytes")
println("Expected: DEF")
print("Real: ")
data = make([]byte, 3)
_, err = eeprom.Read(data)
if err != nil {
println("There was an error in Read:", err)
return
}
for _, char := range data {
print(string(char))
}
println("")
println("\n\r\n\rRead another 3 bytes (from the beginning this time)")
eeprom.Seek(-6, 1)
println("Expected: XXX")
print("Real: ")
data = make([]byte, 3)
_, err = eeprom.Read(data)
if err != nil {
println("There was an error in Read:", err)
return
}
for _, char := range data {
print(string(char))
}
println("")
// Move to the end of memory
eeprom.Seek(-4, 2)
_, err = eeprom.Write([]uint8{89, 90, 89, 90})
if err != nil {
println("There was an error in Write:", err)
return
}
println("\n\r\n\rRead the last 4 bytes of the memory and the 3 of the beginning")
eeprom.Seek(-4, 1)
println("Expected: YZYZXXX")
print("Real: ")
data = make([]byte, 7)
_, err = eeprom.Read(data)
if err != nil {
println("There was an error in Read:", err)
return
}
for _, char := range data {
print(string(char))
}
println("")
}
@@ -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)
}
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"time"
"machine"
"tinygo.org/x/drivers/bh1750"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := bh1750.New(machine.I2C0)
sensor.Configure()
for {
lux := sensor.Illuminance()
println("Illuminance:", lux, "lx")
time.Sleep(500 * time.Millisecond)
}
}
+41
View File
@@ -0,0 +1,41 @@
// Connects to an BlinkM I2C RGB LED.
// http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/blinkm"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
bm := blinkm.New(machine.I2C0)
bm.Configure()
maj, min, _ := bm.Version()
println("Firmware version:", string(maj), string(min))
count := 0
for {
switch count {
case 0:
// Crimson
bm.SetRGB(0xdc, 0x14, 0x3c)
count = 1
case 1:
// MediumPurple
bm.SetRGB(0x93, 0x70, 0xdb)
count = 2
case 2:
// MediumSeaGreen
bm.SetRGB(0x3c, 0xb3, 0x71)
count = 0
}
time.Sleep(100 * time.Millisecond)
}
}
+35
View File
@@ -0,0 +1,35 @@
package main
import (
"machine"
"strconv"
"time"
"tinygo.org/x/drivers/bme280"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := bme280.New(machine.I2C0)
sensor.Configure()
connected := sensor.Connected()
if !connected {
println("BME280 not detected")
}
println("BME280 detected")
for {
temp, _ := sensor.ReadTemperature()
println("Temperature:", strconv.FormatFloat(float64(temp)/1000, 'f', 2, 64), "°C")
press, _ := sensor.ReadPressure()
println("Pressure:", strconv.FormatFloat(float64(press)/100000, 'f', 2, 64), "hPa")
hum, _ := sensor.ReadHumidity()
println("Humidity:", strconv.FormatFloat(float64(hum)/100, 'f', 2, 64), "%")
alt, _ := sensor.ReadAltitude()
println("Altitude:", alt, "m")
time.Sleep(2 * time.Second)
}
}
+46
View File
@@ -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)
}
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"time"
"machine"
"tinygo.org/x/drivers/bmp180"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := bmp180.New(machine.I2C0)
sensor.Configure()
connected := sensor.Connected()
if !connected {
println("BMP180 not detected")
return
}
println("BMP180 detected")
for {
temp, _ := sensor.ReadTemperature()
println("Temperature:", float32(temp)/1000, "°C")
pressure, _ := sensor.ReadPressure()
println("Pressure", float32(pressure)/100000, "hPa")
time.Sleep(2 * time.Second)
}
}
+44
View File
@@ -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)
}
}
+53
View File
@@ -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)
}
}
+40
View File
@@ -0,0 +1,40 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/buzzer"
)
type note struct {
tone float64
duration float64
}
func main() {
speaker := machine.PA30
speaker.Configure(machine.PinConfig{Mode: machine.PinOutput})
speaker.Set(true)
bzrPin := machine.A0
bzrPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
bzr := buzzer.New(bzrPin)
song := []note{
{buzzer.C3, buzzer.Quarter},
{buzzer.D3, buzzer.Quarter},
{buzzer.E3, buzzer.Quarter},
{buzzer.F3, buzzer.Quarter},
{buzzer.G3, buzzer.Quarter},
{buzzer.A3, buzzer.Quarter},
{buzzer.B3, buzzer.Quarter},
{buzzer.C3, buzzer.Quarter},
}
for _, val := range song {
bzr.Tone(val.tone, val.duration)
time.Sleep(10 * time.Millisecond)
}
}
+23
View File
@@ -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)
}
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"machine"
"tinygo.org/x/drivers/ds1307"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
rtc := ds1307.New(machine.I2C0)
read := make([]byte, 5)
for {
rtc.Seek(0, 0)
_, err := rtc.Write([]byte{1, 2, 3, 4, 5})
if err != nil {
println("Error while writing data:", err)
break
}
rtc.Seek(0, 0)
_, err = rtc.Read(read)
if err != nil {
println("Error while reading data:", err)
break
}
for data := range read {
println(data, " ")
}
}
}
+25
View File
@@ -0,0 +1,25 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/ds1307"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
rtc := ds1307.New(machine.I2C0)
rtc.SetTime(time.Date(2019, 5, 15, 20, 34, 12, 0, time.UTC))
for {
t, err := rtc.ReadTime()
if err != nil {
println("Error reading date:", err)
break
}
println(t.Hour(), ":", t.Minute(), ":", t.Second(), " ", t.Day(), "/", t.Month(), "/", t.Year())
}
}
+45
View File
@@ -0,0 +1,45 @@
// Connects to an MAG3110 I2C magnetometer.
package main
import (
"machine"
"time"
"fmt"
"tinygo.org/x/drivers/ds3231"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
rtc := ds3231.New(machine.I2C0)
rtc.Configure()
valid := rtc.IsTimeValid()
if !valid {
date := time.Date(2019, 12, 05, 20, 34, 12, 0, time.UTC)
rtc.SetTime(date)
}
running := rtc.IsRunning()
if !running {
err := rtc.SetRunning(true)
if err != nil {
fmt.Println("Error configuring RTC")
}
}
for {
dt, err := rtc.ReadTime()
if err != nil {
fmt.Println("Error reading date:", err)
} else {
fmt.Printf("Date: %d/%s/%02d %02d:%02d:%02d \r\n", dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second())
}
temp, _ := rtc.ReadTemperature()
fmt.Printf("Temperature: %.2f °C \r\n", float32(temp)/1000)
time.Sleep(time.Second * 1)
}
}
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/easystepper"
)
func main() {
motor := easystepper.New(machine.P13, machine.P15, machine.P14, machine.P16, 200, 75)
motor.Configure()
for {
println("CLOCKWISE")
motor.Move(2050)
time.Sleep(time.Millisecond * 1000)
println("COUNTERCLOCKWISE")
motor.Move(-2050)
time.Sleep(time.Millisecond * 1000)
}
}
+144
View File
@@ -0,0 +1,144 @@
// This is a console to a ESP8266/ESP32 running on the device UART1.
// Allows you to type AT commands from your computer via the microcontroller.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
//
// More information on the Espressif AT command set at:
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
//
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/espat"
)
// change actAsAP to true to act as an access point instead of connecting to one.
const actAsAP = false
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
uart = machine.UART1
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
adaptor *espat.Device
)
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Init esp8266
adaptor = espat.New(uart)
adaptor.Configure()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
println("Type an AT command then press enter:")
prompt()
input := make([]byte, 64)
i := 0
for {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
switch data {
case 13:
// return key
console.Write([]byte("\r\n"))
// send command to ESP8266
input[i] = byte('\r')
input[i+1] = byte('\n')
adaptor.Write(input[:i+2])
// display response
r, _ := adaptor.Response(500)
console.Write(r)
// prompt
prompt()
i = 0
continue
default:
// just echo the character
console.WriteByte(data)
input[i] = data
i++
}
}
time.Sleep(10 * time.Millisecond)
}
}
func prompt() {
print("ESPAT>")
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
// provide access point
func provideAP() {
println("Starting wifi network as access point '" + ssid + "'...")
adaptor.SetWifiMode(espat.WifiModeAP)
adaptor.SetAPConfig(ssid, pass, 7, espat.WifiAPSecurityWPA2_PSK)
println("Ready.")
ip, _ := adaptor.GetAPIP()
println(ip)
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
+130
View File
@@ -0,0 +1,130 @@
// This is a sensor hub that uses a ESP8266/ESP32 running on the device UART1.
// It creates a UDP "server" you can use to get info to/from your computer via the microcontroller.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
//
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/net"
)
// change actAsAP to true to act as an access point instead of connecting to one.
const actAsAP = false
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
uart = machine.UART1
tx = machine.PA22
rx = machine.PA23
adaptor *espat.Device
)
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Init esp8266
adaptor = espat.New(uart)
adaptor.Configure()
readyled := machine.LED
readyled.Configure(machine.PinConfig{Mode: machine.PinOutput})
readyled.High()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
// now make UDP connection
laddr := &net.UDPAddr{Port: 2222}
println("Loading UDP listener...")
conn, _ := net.ListenUDP("UDP", laddr)
println("Waiting for data...")
data := make([]byte, 50)
blink := true
for {
n, _ := conn.Read(data)
if n > 0 {
println(string(data[:n]))
conn.Write([]byte("hello back\r\n"))
}
blink = !blink
if blink {
readyled.High()
} else {
readyled.Low()
}
time.Sleep(500 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting UDP...")
conn.Close()
println("Done.")
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
// provide access point
func provideAP() {
println("Starting wifi network as access point '" + ssid + "'...")
adaptor.SetWifiMode(espat.WifiModeAP)
adaptor.SetAPConfig(ssid, pass, 7, espat.WifiAPSecurityWPA2_PSK)
println("Ready.")
ip, _ := adaptor.GetAPIP()
println(ip)
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
+109
View File
@@ -0,0 +1,109 @@
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
// It creates a UDP connection you can use to get info to/from your computer via the microcontroller.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
//
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/net"
)
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// IP address of the listener aka "hub". Replace with your own info.
const hubIP = "0.0.0.0"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
uart = machine.UART1
tx = machine.PA22
rx = machine.PA23
adaptor *espat.Device
)
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Init esp8266/esp32
adaptor = espat.New(uart)
adaptor.Configure()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
// now make UDP connection
ip := net.ParseIP(hubIP)
raddr := &net.UDPAddr{IP: ip, Port: 2222}
laddr := &net.UDPAddr{Port: 2222}
println("Dialing UDP connection...")
conn, _ := net.DialUDP("udp", laddr, raddr)
for {
// send data
println("Sending data...")
conn.Write([]byte("hello\r\n"))
time.Sleep(1000 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting UDP...")
conn.Close()
println("Done.")
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
+143
View File
@@ -0,0 +1,143 @@
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
// It creates an MQTT connection that publishes a message every second
// to an MQTT broker.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> Internet <--> MQTT broker.
//
// You must install the Paho MQTT package to build this program:
//
// go get -u github.com/eclipse/paho.mqtt.golang
//
package main
import (
"machine"
"math/rand"
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/net/mqtt"
)
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// IP address of the MQTT broker to use. Replace with your own info.
const server = "tcp://test.mosquitto.org:1883"
//const server = "ssl://test.mosquitto.org:8883"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
uart = machine.UART2
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
adaptor *espat.Device
topic = "tinygo"
)
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Init esp8266/esp32
adaptor = espat.New(uart)
adaptor.Configure()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
opts := mqtt.NewClientOptions()
opts.AddBroker(server).SetClientID("tinygo-client-" + randomString(10))
println("Connecting to MQTT broker at", server)
cl := mqtt.NewClient(opts)
if token := cl.Connect(); token.Wait() && token.Error() != nil {
failMessage(token.Error().Error())
}
for {
println("Publishing MQTT message...")
data := []byte("{\"e\":[{ \"n\":\"hello\", \"v\":101 }]}")
token := cl.Publish(topic, 0, false, data)
token.Wait()
if token.Error() != nil {
println(token.Error().Error())
}
time.Sleep(1000 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting MQTT...")
cl.Disconnect(100)
println("Done.")
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
// 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)
}
}
+164
View File
@@ -0,0 +1,164 @@
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
// It creates an MQTT connection that publishes a message every second
// to an MQTT broker.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> Internet <--> MQTT broker.
//
// You must also install the Paho MQTT package to build this program:
//
// go get -u github.com/eclipse/paho.mqtt.golang
//
package main
import (
"fmt"
"machine"
"math/rand"
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/net/mqtt"
)
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// IP address of the MQTT broker to use. Replace with your own info.
//const server = "tcp://test.mosquitto.org:1883"
const server = "ssl://test.mosquitto.org:8883"
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are defaults for the Arduino Nano33 IoT.
uart = machine.UART1
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
adaptor *espat.Device
cl mqtt.Client
topicTx = "tinygo/tx"
topicRx = "tinygo/rx"
)
func subHandler(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("[%s] ", msg.Topic())
fmt.Printf("%s\r\n", msg.Payload())
}
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Init esp8266/esp32
adaptor = espat.New(uart)
adaptor.Configure()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
opts := mqtt.NewClientOptions()
opts.AddBroker(server).SetClientID("tinygo-client-" + randomString(10))
println("Connecting to MQTT broker at", server)
cl = mqtt.NewClient(opts)
if token := cl.Connect(); token.Wait() && token.Error() != nil {
failMessage(token.Error().Error())
}
// subscribe
token := cl.Subscribe(topicRx, 0, subHandler)
token.Wait()
if token.Error() != nil {
failMessage(token.Error().Error())
}
go publishing()
select {}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting MQTT...")
cl.Disconnect(100)
println("Done.")
}
func publishing() {
for {
println("Publishing MQTT message...")
data := []byte("{\"e\":[{ \"n\":\"hello\", \"v\":101 }]}")
token := cl.Publish(topicTx, 0, false, data)
token.Wait()
if token.Error() != nil {
println(token.Error().Error())
}
time.Sleep(1000 * time.Millisecond)
}
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
// 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)
}
}
+112
View File
@@ -0,0 +1,112 @@
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
// It creates a UDP connection you can use to get info to/from your computer via the microcontroller.
//
// In other words:
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
//
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/net"
)
// access point info
const ssid = "YOURSSID"
const pass = "YOURPASS"
// IP address of the server aka "hub". Replace with your own info.
const serverIP = "0.0.0.0"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
uart = machine.UART1
tx = machine.PA22
rx = machine.PA23
adaptor *espat.Device
)
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Init esp8266/esp32
adaptor = espat.New(uart)
adaptor.Configure()
// first check if connected
if connectToESP() {
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
println("")
failMessage("Unable to connect to wifi adaptor.")
return
}
// now make TCP connection
ip := net.ParseIP(serverIP)
raddr := &net.TCPAddr{IP: ip, Port: 8080}
laddr := &net.TCPAddr{Port: 8080}
println("Dialing TCP connection...")
conn, err := net.DialTCP("tcp", laddr, raddr)
if err != nil {
failMessage(err.Error())
}
for {
// send data
println("Sending data...")
conn.Write([]byte("hello\r\n"))
time.Sleep(1000 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting TCP...")
conn.Close()
println("Done.")
}
// connect to ESP8266/ESP32
func connectToESP() bool {
for i := 0; i < 5; i++ {
println("Connecting to wifi adaptor...")
if adaptor.Connected() {
return true
}
time.Sleep(1 * time.Second)
}
return false
}
// connect to access point
func connectToAP() {
println("Connecting to wifi network '" + ssid + "'")
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
failMessage(err.Error())
}
println("Connected.")
ip, err := adaptor.GetClientIP()
if err != nil {
failMessage(err.Error())
}
println(ip)
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
+259
View File
@@ -0,0 +1,259 @@
package console_example
import (
"fmt"
"io"
"machine"
"os"
"strconv"
"strings"
"tinygo.org/x/drivers/flash"
)
const consoleBufLen = 64
const storageBufLen = 512
var (
debug = false
input [consoleBufLen]byte
store [storageBufLen]byte
console = machine.Serial
dev *flash.Device
commands map[string]cmdfunc = map[string]cmdfunc{
"": cmdfunc(noop),
"erase": cmdfunc(erase),
"lsblk": cmdfunc(lsblk),
"write": cmdfunc(write),
"xxd": cmdfunc(xxd),
}
)
type cmdfunc func(argv []string)
const (
StateInput = iota
StateEscape
StateEscBrc
StateCSI
)
func RunFor(device *flash.Device) {
dev = device
dev.Configure(&flash.DeviceConfig{
Identifier: flash.DefaultDeviceIdentifier,
})
prompt()
var state = StateInput
for i := 0; ; {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if debug {
fmt.Printf("\rdata: %x\r\n\r", data)
prompt()
console.Write(input[:i])
}
switch state {
case StateInput:
switch data {
case 0x8:
fallthrough
case 0x7f: // this is probably wrong... works on my machine tho :)
// backspace
if i > 0 {
i -= 1
console.Write([]byte{0x8, 0x20, 0x8})
}
case 13:
// return key
console.Write([]byte("\r\n"))
runCommand(string(input[:i]))
prompt()
i = 0
continue
case 27:
// escape
state = StateEscape
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
if i < (consoleBufLen - 1) {
console.WriteByte(data)
input[i] = data
i++
}
}
}
case StateEscape:
switch data {
case 0x5b:
state = StateEscBrc
default:
state = StateInput
}
default:
// TODO: handle escape sequences
state = StateInput
}
}
}
}
func runCommand(line string) {
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
cmd := argv[0]
cmdfn, ok := commands[cmd]
if !ok {
println("unknown command: " + line)
return
}
cmdfn(argv)
}
func noop(argv []string) {}
func lsblk(argv []string) {
attrs := dev.Attrs()
status1, _ := dev.ReadStatus()
status2, _ := dev.ReadStatus2()
serialNumber1, _ := dev.ReadSerialNumber()
fmt.Printf(
"\n-------------------------------------\r\n"+
" Device Information: \r\n"+
"-------------------------------------\r\n"+
" JEDEC ID: %v\r\n"+
" Serial: %v\r\n"+
" Status 1: %02x\r\n"+
" Status 2: %02x\r\n"+
" \r\n"+
" Max clock speed (MHz): %d\r\n"+
" Has Sector Protection: %t\r\n"+
" Supports Fast Reads: %t\r\n"+
" Supports QSPI Reads: %t\r\n"+
" Supports QSPI Write: %t\r\n"+
" Write Status Split: %t\r\n"+
" Single Status Byte: %t\r\n"+
"-------------------------------------\r\n\r\n",
attrs.JedecID,
serialNumber1,
status1,
status2,
attrs.MaxClockSpeedMHz,
attrs.HasSectorProtection,
attrs.SupportsFastRead,
attrs.SupportsQSPI,
attrs.SupportsQSPIWrites,
attrs.WriteStatusSplit,
attrs.SingleStatusByte,
)
}
func erase(argv []string) {
if len(argv) < 3 {
println("usage: erase <chip|block|sector> <bytes>")
return
}
var err error
var addr uint64 = 0x0
if addr, err = strconv.ParseUint(argv[2], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
if argv[1] == "block" {
if err = dev.EraseBlock(uint32(addr)); err != nil {
println("Block erase error: " + err.Error() + "\r\n")
}
} else if argv[1] == "sector" {
if err = dev.EraseSector(uint32(addr)); err != nil {
println("Sector erase error: " + err.Error() + "\r\n")
}
} else if argv[1] == "chip" {
if err = dev.EraseAll(); err != nil {
println("Chip erase error: " + err.Error() + "\r\n")
}
} else {
println("usage: erase <chip|block|sector> <bytes>")
}
}
func write(argv []string) {
if len(argv) < 3 {
println("usage: write <hex offset> <bytes>")
}
var err error
var addr uint64 = 0x0
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
buf := []byte(argv[2])
if _, err = dev.WriteAt(buf, int64(addr)); err != nil {
println("Write error: " + err.Error() + "\r\n")
}
}
func xxd(argv []string) {
var err error
var addr uint64 = 0x0
var size int = 64
switch len(argv) {
case 3:
if size, err = strconv.Atoi(argv[2]); err != nil {
println("Invalid size argument: " + err.Error() + "\r\n")
return
}
if size > storageBufLen || size < 1 {
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", storageBufLen)
return
}
fallthrough
case 2:
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
fallthrough
case 1:
// no args supplied, so nothing to do here, just use the defaults
default:
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
return
}
buf := store[0:size]
dev.ReadAt(buf, int64(addr))
xxdfprint(os.Stdout, uint32(addr), buf)
}
func xxdfprint(w io.Writer, offset uint32, b []byte) {
var l int
var buf16 = make([]byte, 16)
for i, c := 0, len(b); i < c; i += 16 {
l = i + 16
if l >= c {
l = c
}
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
for j, n := 0, l-i; j < 16; j++ {
if j >= n || !strconv.IsPrint(rune(b[i+j])) {
buf16[j] = '.'
} else {
buf16[j] = b[i+j]
}
}
console.Write(buf16)
println()
}
}
func prompt() {
print("==> ")
}
+21
View File
@@ -0,0 +1,21 @@
package main
import (
"machine"
"tinygo.org/x/drivers/examples/flash/console"
"tinygo.org/x/drivers/flash"
)
func main() {
console_example.RunFor(
flash.NewQSPI(
machine.QSPI_CS,
machine.QSPI_SCK,
machine.QSPI_DATA0,
machine.QSPI_DATA1,
machine.QSPI_DATA2,
machine.QSPI_DATA3,
),
)
}
+20
View File
@@ -0,0 +1,20 @@
package main
import (
"machine"
console_example "tinygo.org/x/drivers/examples/flash/console"
"tinygo.org/x/drivers/flash"
)
func main() {
console_example.RunFor(
flash.NewSPI(
&machine.SPI1,
machine.SPI1_SDO_PIN,
machine.SPI1_SDI_PIN,
machine.SPI1_SCK_PIN,
machine.SPI1_CS_PIN,
),
)
}
+24
View File
@@ -0,0 +1,24 @@
//go:build m5stack_core2
// +build m5stack_core2
package main
import (
"machine"
"tinygo.org/x/drivers/ft6336"
"tinygo.org/x/drivers/i2csoft"
"tinygo.org/x/drivers/touch"
)
// InitDisplay initializes the display of each board.
func initDevices() (touch.Pointer, error) {
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
resistiveTouch.Configure(ft6336.Config{})
resistiveTouch.SetPeriodActive(0x00)
return resistiveTouch, nil
}
+16
View File
@@ -0,0 +1,16 @@
package main
func main() {
touchScreen, _ := initDevices()
for {
touch := touchScreen.ReadTouchPoint()
if touch.Z > 0 {
//X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size
//Z is 24 bit and is typically > 2000 for a touch
println("touch:", touch.X, touch.Y, touch.Z)
//Example of scaling for m5stack-core2's 320x240 display with 320x270 touch area
println("screen:", (touch.X*320)>>16, (touch.Y*270)>>16)
}
}
}
@@ -0,0 +1,55 @@
//go:build m5stack_core2
// +build m5stack_core2
package main
import (
"image/color"
"machine"
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
"tinygo.org/x/drivers/ft6336"
"tinygo.org/x/drivers/i2csoft"
"tinygo.org/x/drivers/ili9341"
"tinygo.org/x/drivers/touch"
)
// InitDisplay initializes the display of each board.
func initDevices() (touchPaintDisplay, touch.Pointer, error) {
machine.SPI2.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40e6,
})
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
axp := axp192.New(i2c)
led := axp.LED
led.Low()
display := ili9341.NewSPI(
machine.SPI2,
machine.LCD_DC_PIN,
machine.LCD_SS_PIN,
machine.NoPin,
)
// configure display
display.Configure(ili9341.Config{
Width: 320,
Height: 240,
DisplayInversion: true,
})
display.FillScreen(color.RGBA{255, 255, 255, 255})
display.SetRotation(ili9341.Rotation0Mirror)
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
resistiveTouch.Configure(ft6336.Config{})
resistiveTouch.SetPeriodActive(0x00)
return display, resistiveTouch, nil
}

Some files were not shown because too many files have changed in this diff Show More