Compare commits

...

11 Commits

Author SHA1 Message Date
deadprogram 159f13974c all: update for release v0.21.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-05 11:15:55 +02:00
Neil Davis 8ddcd69ac0 Add support for '8-step mode' to easystepper
Currently, easystepper driver supports only '4-step mode' (12-23-34-41) when energizing the coils
This does not work with all motors & drivers (e.g. 28BJY-48 & ULN2003)

This commit adds support for 8-step mode (1-12-2-23-3-34-4-41)

Note: this commit breaks backward source compatibility for the factory/constructor functions.
2022-06-12 22:19:42 +02:00
deadprogram 1c038f5183 wifinina: add mutex to prevent communication race problems
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-06-11 10:59:41 +02:00
tgilkerson 36a8b791dc fix(ssd1351): Fix mirrored text on OLED display 2022-06-04 09:13:44 +02:00
Olaf Flebbe df0d0d29a4 ws2812: support thingplus-rp2040 board
Added 125 MHz rp2040 timing
  Added unsafe.Pointer for pointer conversion
2022-05-28 10:22:26 +02:00
Yurii Soldak 3bdab45452 lsm6ds3tr: initial implementation 2022-05-27 07:48:50 +02:00
Olaf Flebbe 9f6783670f sdcard: support thingplus-rp2040
The instances of SPI interfaces SPI0, SPI1, ... are
pointers to SPI types on rp2040 machines, rather plain
values like other machines.

This needs restructuring the sdcard API to take a pointer
to the SPI interface rather the SPI type itself.

Removed waitserial() since it needs modem control lines
not available on most boards
2022-05-24 19:16:34 +02:00
Daniel Esteban ec00fdef9b initial support for UC8151 driver, used in Pimoroni's badger2040 e-paper (#416) 2022-05-24 17:43:07 +02:00
Michael Meister e4951091f4 vl53l1x: Add functions for setting the device address
Implement functions to get and set the device address similar to its
reference implementation in C:
https://github.com/pololu/vl53l1x-arduino/blob/master/VL53L1X.cpp#L28

Signed-off-by: Michael Meister <michael.meister@bytesatwork.ch>
2022-05-18 19:43:30 +02:00
Daniel Esteban 19caee9b76 fixed link to datasheet
fixed temp/humidity values
2022-05-15 07:41:39 +02:00
deadprogram c235509580 scd4x: implement driver for CO2 sensor
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-05-15 07:41:39 +02:00
48 changed files with 2126 additions and 156 deletions
+21
View File
@@ -1,3 +1,24 @@
0.21.0
---
- **new devices**
- lsm6ds3tr: initial implementation
- UC8151: used in Pimoroni's badger2040 e-paper (#416)
- scd4x: implement driver for CO2 sensor
- **enhancements**
- easystepper: Add support for '8-step mode'
- vl53l1x: Add functions for setting the device address
- sdcard: support thingplus-rp2040
- wifinina: add mutex to prevent communication race problems
- **ws2812**
- support thingplus-rp2040 board
- Added 125 MHz rp2040 timing
- Added unsafe.Pointer for pointer conversion
- **bugfixes**
- ssd1351: Fix mirrored text on OLED display
0.20.0
---
- **new devices**
+5 -1
View File
@@ -235,13 +235,17 @@ endif
@md5sum ./build/test.uf2
tinygo build -size short -o ./build/test.hex -target=pico ./examples/irremote/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=badger2040 ./examples/uc8151/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/scd4x/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 keypad4x4 max72xx p1am tone tm1637 \
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 \
ft6336 sx126x ssd1289 irremote
ft6336 sx126x ssd1289 irremote uc8151
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
unit-test:
+87 -84
View File
@@ -52,92 +52,95 @@ func main() {
## Currently supported devices
The following 78 devices are supported.
The following 80 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 |
| [Infrared remote control](https://en.wikipedia.org/wiki/Consumer_IR) | GPIO |
| [IS31FL3731 matrix LED driver](https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf) | I2C |
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
| [L293x motor driver](https://www.ti.com/lit/ds/symlink/l293d.pdf) | GPIO/PWM |
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
| [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 |
| 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 |
| [Infrared remote control](https://en.wikipedia.org/wiki/Consumer_IR) | GPIO |
| [IS31FL3731 matrix LED driver](https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf) | I2C |
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
| [L293x motor driver](https://www.ti.com/lit/ds/symlink/l293d.pdf) | GPIO/PWM |
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
| [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 |
| [LSM6DS3TR accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3tr.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 |
| [SCD4x CO2 Sensor](https://sensirion.com/media/documents/C4B87CE6/627C2DCD/CD_DS_SCD40_SCD41_Datasheet_D1.pdf) | I2C |
| [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 |
| [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 |
| [UC8151 All-in-one driver IC for ESL](https://www.buydisplay.com/download/ic/UC8151C.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
+138 -22
View File
@@ -2,28 +2,76 @@
package easystepper // import "tinygo.org/x/drivers/easystepper"
import (
"errors"
"machine"
"time"
)
// StepMode determines the coil sequence used to perform a single step
type StepMode uint8
// Valid values for StepMode
const (
// ModeFour uses a 'four step' coil sequence (12-23-34-41). This is the default (zero-value) mode
ModeFour StepMode = iota
// ModeEight uses an 'eight step' coil sequence (1-12-2-23-3-34-4-41)
ModeEight
)
// stepCount is a helper function to return the number of steps in a StepMode sequence
func (sm StepMode) stepCount() uint {
switch sm {
default:
fallthrough
case ModeFour:
return 4
case ModeEight:
return 8
}
}
// DeviceConfig contains the configuration data for a single easystepper driver
type DeviceConfig struct {
// Pin1 ... Pin4 determines the pins to configure and use for the device
Pin1, Pin2, Pin3, Pin4 machine.Pin
// StepCount is the number of steps required to perform a full revolution of the stepper motor
StepCount uint
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
RPM uint
// Mode determines the coil sequence used to perform a single step
Mode StepMode
}
// DualDeviceConfig contains the configuration data for a dual easystepper driver
type DualDeviceConfig struct {
DeviceConfig
// Pin5 ... Pin8 determines the pins to configure and use for the second device
Pin5, Pin6, Pin7, Pin8 machine.Pin
}
// Device holds the pins and the delay between steps
type Device struct {
pins [4]machine.Pin
stepDelay int32
stepDelay time.Duration
stepNumber uint8
stepMode StepMode
}
// DualDevice holds information for controlling 2 motors
type DualDevice struct {
devices [2]Device
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),
// New returns a new single easystepper driver given a DeviceConfig
func New(config DeviceConfig) (*Device, error) {
if config.StepCount == 0 || config.RPM == 0 {
return nil, errors.New("config.StepCount and config.RPM must be > 0")
}
return &Device{
pins: [4]machine.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
stepMode: config.Mode,
}, nil
}
// Configure configures the pins of the Device
@@ -34,17 +82,23 @@ func (d *Device) Configure() {
}
// 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),
func NewDual(config DualDeviceConfig) (*DualDevice, error) {
// Create the first device
dev1, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
dual.devices[1] = Device{
pins: [4]machine.Pin{pin5, pin6, pin7, pin8},
stepDelay: 60000000 / (steps * rpm),
// Create the second device
config.DeviceConfig.Pin1 = config.Pin5
config.DeviceConfig.Pin2 = config.Pin6
config.DeviceConfig.Pin3 = config.Pin7
config.DeviceConfig.Pin4 = config.Pin8
dev2, err := New(config.DeviceConfig)
if err != nil {
return nil, err
}
return dual
// Return composite dual device
return &DualDevice{devices: [2]*Device{dev1, dev2}}, nil
}
// Configure configures the pins of the DualDevice
@@ -64,7 +118,7 @@ func (d *Device) Move(steps int32) {
var s int32
d.stepMotor(d.stepNumber)
for s = int32(d.stepNumber); s < steps; s++ {
time.Sleep(time.Duration(d.stepDelay) * time.Microsecond)
time.Sleep(d.stepDelay)
d.moveDirectionSteps(direction, s)
}
}
@@ -101,7 +155,7 @@ func (d *DualDevice) Move(stepsA, stepsB int32) {
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)
time.Sleep(d.devices[0].stepDelay)
d.devices[max].moveDirectionSteps(directions[max], s)
if ((s * stepsB) / stepsA) > minStep {
@@ -119,6 +173,18 @@ func (d *DualDevice) Off() {
// stepMotor changes the pins' state to the correct step
func (d *Device) stepMotor(step uint8) {
switch d.stepMode {
default:
fallthrough
case ModeFour:
d.stepMotor4(step)
case ModeEight:
d.stepMotor8(step)
}
}
// stepMotor4 changes the pins' state to the correct step in 4-step mode
func (d *Device) stepMotor4(step uint8) {
switch step {
case 0:
d.pins[0].High()
@@ -148,13 +214,63 @@ func (d *Device) stepMotor(step uint8) {
d.stepNumber = step
}
// stepMotor8 changes the pins' state to the correct step in 8-step mode
func (d *Device) stepMotor8(step uint8) {
switch step {
case 0:
d.pins[0].High()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].Low()
case 1:
d.pins[0].High()
d.pins[2].High()
d.pins[1].Low()
d.pins[3].Low()
case 2:
d.pins[0].Low()
d.pins[2].High()
d.pins[1].Low()
d.pins[3].Low()
case 3:
d.pins[0].Low()
d.pins[2].High()
d.pins[1].High()
d.pins[3].Low()
case 4:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].High()
d.pins[3].Low()
case 5:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].High()
d.pins[3].High()
case 6:
d.pins[0].Low()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].High()
case 7:
d.pins[0].High()
d.pins[2].Low()
d.pins[1].Low()
d.pins[3].High()
}
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, ...
// Direction true: (4-step mode) 0, 1, 2, 3, 0, 1, 2, ...
// Direction false: (4-step mode) 0, 3, 2, 1, 0, 3, 2, ...
// Direction true: (8-step mode) 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, ...
// Direction false: (8-step mode) 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, ...
func (d *Device) moveDirectionSteps(direction bool, step int32) {
modulus := int32(d.stepMode.stepCount())
if direction {
d.stepMotor(uint8(step % 4))
d.stepMotor(uint8(step % modulus))
} else {
d.stepMotor(uint8((step + 2*(step%2)) % 4))
d.stepMotor(uint8(((-step % modulus) + modulus) % modulus))
}
}
+5 -1
View File
@@ -8,7 +8,11 @@ import (
)
func main() {
motor := easystepper.New(machine.P13, machine.P15, machine.P14, machine.P16, 200, 75)
config := easystepper.DeviceConfig{
Pin1: machine.P13, Pin2: machine.P15, Pin3: machine.P14, Pin4: machine.P16,
StepCount: 200, RPM: 75, Mode: easystepper.ModeFour,
}
motor, _ := easystepper.New(config)
motor.Configure()
for {
+37
View File
@@ -0,0 +1,37 @@
// Connects to an LSM6DS3TR I2C a 6 axis Inertial Measurement Unit (IMU)
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/lsm6ds3tr"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
accel := lsm6ds3tr.New(machine.I2C0)
err := accel.Configure(lsm6ds3tr.Configuration{})
if err != nil {
for {
println("Failed to configure", err.Error())
time.Sleep(time.Second)
}
}
for {
if !accel.Connected() {
println("LSM6DS3TR not connected")
time.Sleep(time.Second)
continue
}
x, y, z, _ := accel.ReadAcceleration()
println("Acceleration:", float32(x)/1000000, float32(y)/1000000, float32(z)/1000000)
x, y, z, _ = accel.ReadRotation()
println("Gyroscope:", float32(x)/1000000, float32(y)/1000000, float32(z)/1000000)
x, _ = accel.ReadTemperature()
println("Degrees C", float32(x)/1000, "\n\n")
time.Sleep(time.Millisecond * 1000)
}
}
+39
View File
@@ -0,0 +1,39 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/scd4x"
)
var (
i2c = machine.I2C0
sensor = scd4x.New(i2c)
)
func main() {
time.Sleep(1500 * time.Millisecond)
i2c.Configure(machine.I2CConfig{})
if err := sensor.Configure(); err != nil {
println(err)
}
time.Sleep(1500 * time.Millisecond)
if err := sensor.StartPeriodicMeasurement(); err != nil {
println(err)
}
time.Sleep(1500 * time.Millisecond)
for {
co2, err := sensor.ReadCO2()
if err != nil {
println(err)
}
println("CO2", co2)
time.Sleep(time.Second)
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI1
spi = &machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -9
View File
@@ -9,7 +9,7 @@ import (
)
var (
spi machine.SPI
spi *machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
@@ -18,7 +18,6 @@ var (
)
func main() {
waitSerial()
fmt.Printf("sdcard console\r\n")
led := ledPin
@@ -42,10 +41,3 @@ func main() {
time.Sleep(200 * time.Millisecond)
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SDCARD_SPI
spi = &machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
@@ -0,0 +1,18 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SPI1_SCK_PIN
sdoPin = machine.SPI1_SDO_PIN
sdiPin = machine.SPI1_SDI_PIN
csPin = machine.GPIO9
ledPin = machine.LED
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI2
spi = &machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI1
spi = &machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -10
View File
@@ -11,7 +11,7 @@ import (
)
var (
spi machine.SPI
spi *machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
@@ -20,8 +20,6 @@ var (
)
func main() {
waitSerial()
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
err := sd.Configure()
if err != nil {
@@ -40,10 +38,3 @@ func main() {
console.RunFor(&sd, filesystem)
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SDCARD_SPI
spi = &machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
@@ -0,0 +1,18 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SPI1_SCK_PIN
sdoPin = machine.SPI1_SDO_PIN
sdiPin = machine.SPI1_SDI_PIN
csPin = machine.GPIO9
ledPin = machine.LED
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func init() {
spi = machine.SPI2
spi = &machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
+49
View File
@@ -0,0 +1,49 @@
package main
import (
"image/color"
"machine"
"tinygo.org/x/drivers/uc8151"
)
var display uc8151.Device
var led machine.Pin
func main() {
led = machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 12000000,
SCK: machine.EPD_SCK_PIN,
SDO: machine.EPD_SDO_PIN,
})
display = uc8151.New(machine.SPI0, machine.EPD_CS_PIN, machine.EPD_DC_PIN, machine.EPD_RESET_PIN, machine.EPD_BUSY_PIN)
display.Configure(uc8151.Config{
Rotation: uc8151.ROTATION_270,
Speed: uc8151.MEDIUM,
Blocking: true,
})
black := color.RGBA{1, 1, 1, 255}
display.ClearBuffer()
display.Display()
for i := int16(0); i < 37; i++ {
for j := int16(0); j < 16; j++ {
if (i+j)%2 == 0 {
showRect(i*8, j*8, 8, 8, black)
}
}
}
display.Display()
}
func showRect(x int16, y int16, w int16, h int16, c color.RGBA) {
for i := x; i < x+w; i++ {
for j := y; j < y+h; j++ {
display.SetPixel(i, j, c)
}
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3
// +build !digispark,!arduino,!qtpy,!m5stamp_c3
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3 && !thingplus_rp2040
// +build !digispark,!arduino,!qtpy,!m5stamp_c3,!thingplus_rp2040
package main
+13
View File
@@ -0,0 +1,13 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
import "machine"
// This is the pin assignment for the internal neopixel of the
// Sparkfun thingplus rp2040.
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.GPIO8
var led = machine.LED
+189
View File
@@ -0,0 +1,189 @@
// Package lsm6ds3tr implements a driver for the LSM6DS3TR
// a 6 axis Inertial Measurement Unit (IMU)
//
// Datasheet: https://www.st.com/resource/en/datasheet/lsm6ds3tr.pdf
//
package lsm6ds3tr // import "tinygo.org/x/drivers/lsm6ds3tr"
import (
"errors"
"tinygo.org/x/drivers"
)
type AccelRange uint8
type AccelSampleRate uint8
type AccelBandwidth uint8
type GyroRange uint8
type GyroSampleRate uint8
// Device wraps an I2C connection to a LSM6DS3TR device.
type Device struct {
bus drivers.I2C
Address uint16
accelRange AccelRange
accelSampleRate AccelSampleRate
gyroRange GyroRange
gyroSampleRate GyroSampleRate
buf [6]uint8
}
// Configuration for LSM6DS3TR device.
type Configuration struct {
AccelRange AccelRange
AccelSampleRate AccelSampleRate
AccelBandWidth AccelBandwidth
GyroRange GyroRange
GyroSampleRate GyroSampleRate
IsPedometer bool
ResetStepCounter bool
}
var errNotConnected = errors.New("lsm6ds3tr: failed to communicate with acel/gyro sensor")
// New creates a new LSM6DS3TR 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) doConfigure(cfg Configuration) (err error) {
// Verify unit communication
if !d.Connected() {
return errNotConnected
}
if cfg.AccelRange != 0 {
d.accelRange = cfg.AccelRange
} else {
d.accelRange = ACCEL_2G
}
if cfg.AccelSampleRate != 0 {
d.accelSampleRate = cfg.AccelSampleRate
} else {
d.accelSampleRate = ACCEL_SR_104
}
if cfg.GyroRange != 0 {
d.gyroRange = cfg.GyroRange
} else {
d.gyroRange = GYRO_2000DPS
}
if cfg.GyroSampleRate != 0 {
d.gyroSampleRate = cfg.GyroSampleRate
} else {
d.gyroSampleRate = GYRO_SR_104
}
data := d.buf[:1]
// Configure accelerometer
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
// Set ODR bit
err = d.bus.ReadRegister(uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = d.bus.WriteRegister(uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = d.bus.WriteRegister(uint8(d.Address), CTRL2_G, data)
if err != nil {
return
}
return nil
}
// Connected returns whether a LSM6DS3TR has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x6A
}
// ReadAcceleration reads the current acceleration from the device and returns
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_XL, data)
if err != nil {
return
}
// k comes from "Table 3. Mechanical characteristics" 3 of the datasheet * 1000
k := int32(61) // 2G
if d.accelRange == ACCEL_4G {
k = 122
} else if d.accelRange == ACCEL_8G {
k = 244
} else if d.accelRange == ACCEL_16G {
k = 488
}
x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * k
y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * k
z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * k
return
}
// ReadRotation reads the current rotation from the device and returns it in
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = d.bus.ReadRegister(uint8(d.Address), OUTX_L_G, data)
if err != nil {
return
}
// k comes from "Table 3. Mechanical characteristics" 3 of the datasheet * 1000
k := int32(4375) // 125DPS
if d.gyroRange == GYRO_245DPS {
k = 8750
} else if d.gyroRange == GYRO_500DPS {
k = 17500
} else if d.gyroRange == GYRO_1000DPS {
k = 35000
} else if d.gyroRange == GYRO_2000DPS {
k = 70000
}
x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * k
y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * k
z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * k
return
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = d.bus.ReadRegister(uint8(d.Address), OUT_TEMP_L, data)
if err != nil {
return
}
// From "Table 5. Temperature sensor characteristics"
// temp = value/256 + 25
t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
return
}
+9
View File
@@ -0,0 +1,9 @@
//go:build !xiao_ble
// +build !xiao_ble
package lsm6ds3tr
// Configure sets up the device for communication.
func (d *Device) Configure(cfg Configuration) error {
return d.doConfigure(cfg)
}
+35
View File
@@ -0,0 +1,35 @@
//go:build xiao_ble
// +build xiao_ble
package lsm6ds3tr
import (
"device/nrf"
"machine"
"time"
)
// Configure sets up the device for communication.
func (d *Device) Configure(cfg Configuration) error {
// Following lines are XIAO BLE Sense specific, they have nothing to do with sensor per se
// Implementation adapted from https://github.com/Seeed-Studio/Seeed_Arduino_LSM6DS3/blob/master/LSM6DS3.cpp#L68-L77
// Special mode for IMU power pin on this board.
// Can not use pin.Configure() directly due to special mode and 32 bit size
pinConfig := uint32(nrf.GPIO_PIN_CNF_DIR_Output<<nrf.GPIO_PIN_CNF_DIR_Pos) |
uint32(nrf.GPIO_PIN_CNF_INPUT_Disconnect<<nrf.GPIO_PIN_CNF_INPUT_Pos) |
uint32(nrf.GPIO_PIN_CNF_PULL_Disabled<<nrf.GPIO_PIN_CNF_PULL_Pos) |
uint32(nrf.GPIO_PIN_CNF_DRIVE_H0H1<<nrf.GPIO_PIN_CNF_DRIVE_Pos) |
uint32(nrf.GPIO_PIN_CNF_SENSE_Disabled<<nrf.GPIO_PIN_CNF_SENSE_Pos)
nrf.P1.PIN_CNF[8].Set(pinConfig) // LSM_PWR == P1_08
// Enable IMU
machine.LSM_PWR.High()
// Wait a moment
time.Sleep(10 * time.Millisecond)
// Common initialisation code
return d.doConfigure(cfg)
}
+79
View File
@@ -0,0 +1,79 @@
package lsm6ds3tr
// Constants/addresses used for I2C.
// The I2C address which this device listens to.
const Address = 0x6A
const (
WHO_AM_I = 0x0F
STATUS = 0x1E
CTRL1_XL = 0x10
CTRL2_G = 0x11
CTRL3_C = 0x12
CTRL4_C = 0x13
CTRL5_C = 0x14
CTRL6_C = 0x15
CTRL7_G = 0x16
CTRL8_XL = 0x17
CTRL9_XL = 0x18
CTRL10_C = 0x19
OUTX_L_G = 0x22
OUTX_H_G = 0x23
OUTY_L_G = 0x24
OUTY_H_G = 0x25
OUTZ_L_G = 0x26
OUTZ_H_G = 0x27
OUTX_L_XL = 0x28
OUTX_H_XL = 0x29
OUTY_L_XL = 0x2A
OUTY_H_XL = 0x2B
OUTZ_L_XL = 0x2C
OUTZ_H_XL = 0x2D
OUT_TEMP_L = 0x20
OUT_TEMP_H = 0x21
BW_SCAL_ODR_DISABLED = 0x00
BW_SCAL_ODR_ENABLED = 0x80
STEP_TIMESTAMP_L = 0x49
STEP_TIMESTAMP_H = 0x4A
STEP_COUNTER_L = 0x4B
STEP_COUNTER_H = 0x4C
STEP_COUNT_DELTA = 0x15
TAP_CFG = 0x58
INT1_CTRL = 0x0D
ACCEL_2G AccelRange = 0x00
ACCEL_4G AccelRange = 0x08
ACCEL_8G AccelRange = 0x0C
ACCEL_16G AccelRange = 0x04
ACCEL_SR_OFF AccelSampleRate = 0x00
ACCEL_SR_13 AccelSampleRate = 0x10
ACCEL_SR_26 AccelSampleRate = 0x20
ACCEL_SR_52 AccelSampleRate = 0x30
ACCEL_SR_104 AccelSampleRate = 0x40
ACCEL_SR_208 AccelSampleRate = 0x50
ACCEL_SR_416 AccelSampleRate = 0x60
ACCEL_SR_833 AccelSampleRate = 0x70
ACCEL_SR_1666 AccelSampleRate = 0x80
ACCEL_SR_3332 AccelSampleRate = 0x90
ACCEL_SR_6664 AccelSampleRate = 0xA0
GYRO_125DPS GyroRange = 0x02
GYRO_245DPS GyroRange = 0x00
GYRO_500DPS GyroRange = 0x04
GYRO_1000DPS GyroRange = 0x08
GYRO_2000DPS GyroRange = 0x0C
GYRO_SR_OFF GyroSampleRate = 0x00
GYRO_SR_13 GyroSampleRate = 0x10
GYRO_SR_26 GyroSampleRate = 0x20
GYRO_SR_52 GyroSampleRate = 0x30
GYRO_SR_104 GyroSampleRate = 0x40
GYRO_SR_208 GyroSampleRate = 0x50
GYRO_SR_416 GyroSampleRate = 0x60
GYRO_SR_833 GyroSampleRate = 0x70
GYRO_SR_1666 GyroSampleRate = 0x80
GYRO_SR_3332 GyroSampleRate = 0x90
GYRO_SR_6664 GyroSampleRate = 0xA0
)
+25
View File
@@ -0,0 +1,25 @@
package scd4x
const (
// Address is default I2C address.
Address = 0x62
CmdDataReady = 0xE4B8
CmdFactoryReset = 0x3632
CmdForcedRecal = 0x362F
CmdGetAltitude = 0x2322
CmdGetASCE = 0x2313
CmdGetTempOffset = 0x2318
CmdPersistSettings = 0x3615
CmdReadMeasurement = 0xEC05
CmdReinit = 0x3646
CmdSelfTest = 0x3639
CmdSerialNumber = 0x3682
CmdSetAltitude = 0x2427
CmdSetASCE = 0x2416
CmdSetPressure = 0xE000
CmdSetTempOffset = 0x241D
CmdStartLowPowerPeriodicMeasurement = 0x21AC
CmdStartPeriodicMeasurement = 0x21B1
CmdStopPeriodicMeasurement = 0x3F86
)
+180
View File
@@ -0,0 +1,180 @@
// Package scd4x provides a driver for the scd4x I2C envrironment sensor.
//
// Datasheet: https://sensirion.com/media/documents/C4B87CE6/627C2DCD/CD_DS_SCD40_SCD41_Datasheet_D1.pdf
//
// This driver is heavily influenced by the scd4x code from Adafruit for CircuitPython:
// https://github.com/adafruit/Adafruit_CircuitPython_SCD4X
// Thank you!
//
package scd4x // import "tinygo.org/x/drivers/scd4x"
import (
"encoding/binary"
"time"
"tinygo.org/x/drivers"
)
type Device struct {
bus drivers.I2C
tx []byte
rx []byte
Address uint8
// used to cache the most recent readings
co2 uint16
temperature uint16
humidity uint16
}
// New returns SCD4x device for the provided I2C bus using default address of 0x62.
func New(i2c drivers.I2C) *Device {
return &Device{
bus: i2c,
tx: make([]byte, 5),
rx: make([]byte, 18),
Address: Address,
}
}
// Configure the device.
func (d *Device) Configure() (err error) {
if err := d.StopPeriodicMeasurement(); err != nil {
return err
}
time.Sleep(500 * time.Millisecond)
// reset the chip
if err := d.sendCommand(CmdReinit); err != nil {
return err
}
time.Sleep(20 * time.Millisecond)
return
}
// Connected returns whether sensor has been found.
func (d *Device) Connected() bool {
// TODO: something here to check if the sensor is connected
return true
}
// DataReady checks the sensor to see if new data is available.
func (d *Device) DataReady() (bool, error) {
if err := d.sendCommandWithResult(CmdDataReady, d.rx[0:3]); err != nil {
return false, err
}
return !(d.rx[0]&0x07 == 0 && d.rx[1] == 0), nil
}
// StartPeriodicMeasurement puts the sensor into working mode, about 5s per measurement.
func (d *Device) StartPeriodicMeasurement() error {
return d.sendCommand(CmdStartPeriodicMeasurement)
}
// StopPeriodicMeasurement stops the sensor reading data.
func (d *Device) StopPeriodicMeasurement() error {
return d.sendCommand(CmdStopPeriodicMeasurement)
}
// StartLowPowerPeriodicMeasurement puts the sensor into low power working mode,
// about 30s per measurement.
func (d *Device) StartLowPowerPeriodicMeasurement() error {
return d.sendCommand(CmdStartLowPowerPeriodicMeasurement)
}
// ReadData reads the data from the sensor and caches it.
func (d *Device) ReadData() error {
if err := d.sendCommandWithResult(CmdReadMeasurement, d.rx[0:9]); err != nil {
return err
}
d.co2 = binary.BigEndian.Uint16(d.rx[0:2])
d.temperature = binary.BigEndian.Uint16(d.rx[3:5])
d.humidity = binary.BigEndian.Uint16(d.rx[6:8])
return nil
}
// ReadCO2 returns the CO2 concentration in PPM (parts per million).
func (d *Device) ReadCO2() (co2 int32, err error) {
ok, err := d.DataReady()
if err != nil {
return 0, err
}
if ok {
err = d.ReadData()
}
return int32(d.co2), err
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (temperature int32, err error) {
ok, err := d.DataReady()
if err != nil {
return 0, err
}
if ok {
err = d.ReadData()
}
// temp = -45 + 175 * value / 2¹⁶
return (-1 * 45000) + (21875 * (int32(d.temperature)) / 8192), err
}
// ReadTempC returns the value in the temperature value in Celsius.
func (d *Device) ReadTempC() float32 {
t, _ := d.ReadTemperature()
return float32(t) / 1000
}
// ReadTempF returns the value in the temperature value in Fahrenheit.
func (d *Device) ReadTempF() float32 {
return d.ReadTempC()*1.8 + 32.0
}
// ReadHumidity returns the current relative humidity in %rH.
func (d *Device) ReadHumidity() (humidity int32, err error) {
ok, err := d.DataReady()
if err != nil {
return 0, err
}
if ok {
err = d.ReadData()
}
// humidity = 100 * value / 2¹⁶
return (25 * int32(d.humidity)) / 16384, err
}
func (d *Device) sendCommand(command uint16) error {
binary.BigEndian.PutUint16(d.tx[0:], command)
return d.bus.Tx(uint16(d.Address), d.tx[0:2], nil)
}
func (d *Device) sendCommandWithValue(command, value uint16) error {
binary.BigEndian.PutUint16(d.tx[0:], command)
binary.BigEndian.PutUint16(d.tx[2:], value)
d.tx[4] = crc8(d.tx[2:4])
return d.bus.Tx(uint16(d.Address), d.tx[0:5], nil)
}
func (d *Device) sendCommandWithResult(command uint16, result []byte) error {
binary.BigEndian.PutUint16(d.tx[0:], command)
if err := d.bus.Tx(uint16(d.Address), d.tx[0:2], nil); err != nil {
return err
}
time.Sleep(time.Millisecond)
return d.bus.Tx(uint16(d.Address), nil, result)
}
func crc8(buf []byte) uint8 {
var crc uint8 = 0xff
for _, b := range buf {
crc ^= b
for i := 0; i < 8; i++ {
if crc&0x80 != 0 {
crc = (crc << 1) ^ 0x31
} else {
crc <<= 1
}
}
}
return crc & 0xff
}
+15
View File
@@ -0,0 +1,15 @@
package scd4x
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))
}
+2 -2
View File
@@ -28,7 +28,7 @@ var (
)
type Device struct {
bus machine.SPI
bus *machine.SPI
sck machine.Pin
sdo machine.Pin
sdi machine.Pin
@@ -41,7 +41,7 @@ type Device struct {
CSD *CSD
}
func New(b machine.SPI, sck, sdo, sdi, cs machine.Pin) Device {
func New(b *machine.SPI, sck, sdo, sdi, cs machine.Pin) Device {
return Device{
bus: b,
cs: cs,
+1 -1
View File
@@ -103,7 +103,7 @@ func (d *Device) Configure(cfg Config) {
d.Command(SET_MUX_RATIO)
d.Data(0x7F)
d.Command(SET_REMAP_COLORDEPTH)
d.Data(0x72)
d.Data(0x62)
d.Command(SET_COLUMN_ADDRESS)
d.Data(0x00)
d.Data(0x7F)
+153
View File
@@ -0,0 +1,153 @@
package uc8151
// Registers
const (
// Display resolution
EPD_WIDTH = 128
EPD_HEIGHT = 296
PSR = 0x00
PWR = 0x01
POF = 0x02
PFS = 0x03
PON = 0x04
PMES = 0x05
BTST = 0x06
DSLP = 0x07
DTM1 = 0x10
DSP = 0x11
DRF = 0x12
DTM2 = 0x13
LUT_VCOM = 0x20
LUT_WW = 0x21
LUT_BW = 0x22
LUT_WB = 0x23
LUT_BB = 0x24
PLL = 0x30
TSC = 0x40
TSE = 0x41
TSR = 0x43
TSW = 0x42
CDI = 0x50
LPD = 0x51
TCON = 0x60
TRES = 0x61
REV = 0x70
FLG = 0x71
AMV = 0x80
VV = 0x81
VDCS = 0x82
PTL = 0x90
PTIN = 0x91
PTOU = 0x92
PGM = 0xa0
APG = 0xa1
ROTP = 0xa2
CCSET = 0xe0
PWS = 0xe3
TSSET = 0xe5
RES_96x230 = 0b00000000
RES_96x252 = 0b01000000
RES_128x296 = 0b10000000
RES_160x296 = 0b11000000
LUT_OTP = 0b00000000
LUT_REG = 0b00100000
FORMAT_BWR = 0b00000000
FORMAT_BW = 0b00010000
SCAN_DOWN = 0b00000000
SCAN_UP = 0b00001000
SHIFT_LEFT = 0b00000000
SHIFT_RIGHT = 0b00000100
BOOSTER_OFF = 0b00000000
BOOSTER_ON = 0b00000010
RESET_SOFT = 0b00000000
RESET_NONE = 0b00000001
VDS_EXTERNAL = 0b00000000
VDS_INTERNAL = 0b00000010
VDG_EXTERNAL = 0b00000000
VDG_INTERNAL = 0b00000001
VCOM_VD = 0b00000000
VCOM_VG = 0b00000100
VGHL_16V = 0b00000000
VGHL_15V = 0b00000001
VGHL_14V = 0b00000010
VGHL_13V = 0b00000011
START_10MS = 0b00000000
START_20MS = 0b01000000
START_30MS = 0b10000000
START_40MS = 0b11000000
STRENGTH_1 = 0b00000000
STRENGTH_2 = 0b00001000
STRENGTH_3 = 0b00010000
STRENGTH_4 = 0b00011000
STRENGTH_5 = 0b00100000
STRENGTH_6 = 0b00101000
STRENGTH_7 = 0b00110000
STRENGTH_8 = 0b00111000
OFF_0_27US = 0b00000000
OFF_0_34US = 0b00000001
OFF_0_40US = 0b00000010
OFF_0_54US = 0b00000011
OFF_0_80US = 0b00000100
OFF_1_54US = 0b00000101
OFF_3_34US = 0b00000110
OFF_6_58US = 0b00000111
FRAMES_1 = 0b00000000
FRAMES_2 = 0b00010000
FRAMES_3 = 0b00100000
FRAMES_4 = 0b00110000
TEMP_INTERNAL = 0b00000000
TEMP_EXTERNAL = 0b10000000
OFFSET_0 = 0b00000000
OFFSET_1 = 0b00000001
OFFSET_2 = 0b00000010
OFFSET_3 = 0b00000011
OFFSET_4 = 0b00000100
OFFSET_5 = 0b00000101
OFFSET_6 = 0b00000110
OFFSET_7 = 0b00000111
OFFSET_MIN_8 = 0b00001000
OFFSET_MIN_7 = 0b00001001
OFFSET_MIN_6 = 0b00001010
OFFSET_MIN_5 = 0b00001011
OFFSET_MIN_4 = 0b00001100
OFFSET_MIN_3 = 0b00001101
OFFSET_MIN_2 = 0b00001110
OFFSET_MIN_1 = 0b00001111
HZ_29 = 0b00111111
HZ_33 = 0b00111110
HZ_40 = 0b00111101
HZ_50 = 0b00111100
HZ_67 = 0b00111011
HZ_100 = 0b00111010
HZ_200 = 0b00111001
NO_ROTATION Rotation = 0
ROTATION_90 Rotation = 1 // 90 degrees clock-wise rotation
ROTATION_180 Rotation = 2
ROTATION_270 Rotation = 3
DEFAULT Speed = 0
MEDIUM Speed = 1
FAST Speed = 2
TURBO Speed = 3
)
+634
View File
@@ -0,0 +1,634 @@
// Package uc8151 implements a driver for e-ink displays controlled by UC8151
//
// Inspired by https://github.com/pimoroni/pimoroni-pico/blob/main/drivers/uc8151/uc8151.cpp
// Datasheet: https://www.buydisplay.com/download/ic/UC8151C.pdf
//
package uc8151 // import "tinygo.org/x/drivers/uc8151"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
)
type Config struct {
Width int16
Height int16
Rotation Rotation // Rotation is clock-wise
Speed Speed // Value from DEFAULT, MEDIUM, FAST, TURBO
Blocking bool
}
type Device struct {
bus drivers.SPI
cs machine.Pin
dc machine.Pin
rst machine.Pin
busy machine.Pin
width int16
height int16
buffer []uint8
bufferLength uint32
rotation Rotation
speed Speed
blocking bool
}
type Rotation uint8
type Speed uint8
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
return Device{
bus: bus,
cs: csPin,
dc: dcPin,
rst: rstPin,
busy: busyPin,
}
}
// Configure sets up the device.
func (d *Device) Configure(cfg Config) {
if cfg.Width != 0 {
d.width = cfg.Width
} else {
d.width = EPD_WIDTH
}
if cfg.Height != 0 {
d.height = cfg.Height
} else {
d.height = EPD_HEIGHT
}
d.rotation = cfg.Rotation
d.speed = cfg.Speed
d.blocking = cfg.Blocking
d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8
d.buffer = make([]uint8, d.bufferLength)
for i := uint32(0); i < d.bufferLength; i++ {
d.buffer[i] = 0xFF
}
d.Reset()
d.SendCommand(PSR)
if d.speed == 0 {
d.SendData(RES_128x296 | LUT_OTP | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP)
} else {
d.SendData(RES_128x296 | LUT_REG | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP)
}
d.SetLUT(d.speed)
d.SendCommand(PWR)
d.SendData(VDS_INTERNAL | VDG_INTERNAL)
d.SendData(VCOM_VG | VGHL_16V)
d.SendData(0x2B)
d.SendData(0x2B)
d.SendData(0x2B)
d.SendCommand(PON)
d.WaitUntilIdle()
d.SendCommand(BTST)
d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US)
d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US)
d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US)
d.SendCommand(PFS)
d.SendData(FRAMES_1)
d.SendCommand(TSE)
d.SendData(TEMP_INTERNAL | OFFSET_0)
d.SendCommand(TCON)
d.SendData(0x22)
d.SendCommand(CDI)
d.SendData(0x4C) // 4C //5C
d.SendCommand(PLL)
d.SendData(HZ_100)
d.SendCommand(POF)
d.WaitUntilIdle()
}
// Reset resets the device
func (d *Device) Reset() {
d.rst.Low()
time.Sleep(10 * time.Millisecond)
d.rst.High()
time.Sleep(10 * time.Millisecond)
d.WaitUntilIdle()
}
// PowerOff power off the device
func (d *Device) PowerOff() {
d.SendCommand(POF)
}
// SendCommand sends a command to the display
func (d *Device) SendCommand(command uint8) {
d.sendDataCommand(true, command)
}
// SendData sends a data byte to the display
func (d *Device) SendData(data uint8) {
d.sendDataCommand(false, data)
}
// sendDataCommand sends image data or a command to the screen
func (d *Device) sendDataCommand(isCommand bool, data uint8) {
if isCommand {
d.dc.Low()
} else {
d.dc.High()
}
d.cs.Low()
d.bus.Transfer(data)
d.cs.High()
}
// SetPixel modifies the internal buffer in a single pixel.
// The display have 2 colors: black and white
// We use RGBA(0,0,0, 255) as white (transparent)
// Anything else as black
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
x, y = d.xy(x, y)
if x < 0 || x >= d.width || y < 0 || y >= d.height {
return
}
byteIndex := x/8 + y*(d.width/8)
if c.R == 0 && c.G == 0 && c.B == 0 { // TRANSPARENT / WHITE
d.buffer[byteIndex] &^= 0x80 >> uint8(x%8)
} else { // WHITE / EMPTY
d.buffer[byteIndex] |= 0x80 >> uint8(x%8)
}
}
// Display sends the buffer to the screen.
func (d *Device) Display() error {
if d.blocking {
d.WaitUntilIdle()
}
d.SendCommand(PON)
d.SendCommand(PTOU)
d.SendCommand(DTM2)
for i := uint32(0); i < d.bufferLength; i++ {
d.SendData(d.buffer[i])
}
d.SendCommand(DSP)
d.SendCommand(DRF)
if d.blocking {
d.WaitUntilIdle()
d.PowerOff()
}
return nil
}
// DisplayRect sends only an area of the buffer to the screen.
// The rectangle points need to be a multiple of 8 in the screen.
// They might not work as expected if the screen is rotated.
func (d *Device) DisplayRect(x int16, y int16, width int16, height int16) error {
if d.blocking {
d.WaitUntilIdle()
}
x, y = d.xy(x, y)
if x < 0 || y < 0 || x >= d.width || y >= d.height || width < 0 || height < 0 {
return errors.New("wrong rectangle")
}
if d.rotation == ROTATION_90 {
width, height = height, width
x -= width
} else if d.rotation == ROTATION_180 {
x -= width - 1
y -= height - 1
} else if d.rotation == ROTATION_270 {
width, height = height, width
y -= height
}
x &= 0xF8
width &= 0xF8
width = x + width // reuse variables
if width >= d.width {
width = d.width
}
height = y + height
if height > d.height {
height = d.height
}
d.SendCommand(PON)
d.SendCommand(PTIN)
d.SendCommand(PTL)
d.SendData(uint8(x))
d.SendData(uint8(x+width-1) | 0x07)
d.SendData(uint8(y >> 8))
d.SendData(uint8(y))
d.SendData(uint8((y + height - 1) >> 8))
d.SendData(uint8(y + height - 1))
d.SendData(0x01)
d.SendCommand(DTM2)
x = x / 8
width = width / 8
for ; y < height; y++ {
for i := x; i < width; i++ {
d.SendData(d.buffer[i+y*(d.width/8)])
}
}
d.SendCommand(DSP)
d.SendCommand(DRF)
if d.blocking {
d.WaitUntilIdle()
d.PowerOff()
}
return nil
}
// ClearDisplay erases the device SRAM
func (d *Device) ClearDisplay() {
d.ClearBuffer()
d.Display()
}
// WaitUntilIdle waits until the display is ready
func (d *Device) WaitUntilIdle() {
for !d.busy.Get() {
time.Sleep(100 * time.Millisecond)
}
}
// IsBusy returns the busy status of the display
func (d *Device) IsBusy() bool {
return d.busy.Get()
}
// ClearBuffer sets the buffer to 0xFF (white)
func (d *Device) ClearBuffer() {
for i := uint32(0); i < d.bufferLength; i++ {
d.buffer[i] = 0x00
}
}
// Size returns the current size of the display.
func (d *Device) Size() (w, h int16) {
if d.rotation == ROTATION_90 || d.rotation == ROTATION_270 {
return d.height, d.width
}
return d.width, d.height
}
// SetRotation changes the rotation (clock-wise) of the device
func (d *Device) SetRotation(rotation Rotation) {
d.rotation = rotation
}
// SetBlocking changes the blocking flag of the device
func (d *Device) SetBlocking(blocking bool) {
d.blocking = blocking
}
// xy chages the coordinates according to the rotation
func (d *Device) xy(x, y int16) (int16, int16) {
switch d.rotation {
case NO_ROTATION:
return x, y
case ROTATION_90:
return d.width - y - 1, x
case ROTATION_180:
return d.width - x - 1, d.height - y - 1
case ROTATION_270:
return y, d.height - x - 1
}
return x, y
}
// SetSpeed changes the refresh speed of the device (the display needs to re-configure)
func (d *Device) SetSpeed(speed Speed) {
d.Configure(Config{
Width: d.width,
Height: d.height,
Rotation: d.rotation,
Speed: speed,
Blocking: d.blocking,
})
}
// Invert sets the display' invert mode
func (d *Device) Invert(invert bool) {
if invert {
d.SendData(0x5C)
} else {
d.SendData(0x4C)
}
}
// SetLUT sets the look up tables for full or partial updates
func (d *Device) SetLUT(speed Speed) {
switch speed {
case MEDIUM:
var lut = [44]uint8{
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x23, 0x23, 0x00, 0x00, 0x02,
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
}
d.SendCommand(LUT_VCOM)
for i := 0; i < 44; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
break
case FAST:
var lut = [44]uint8{
0x00, 0x04, 0x04, 0x07, 0x00, 0x01,
0x00, 0x0c, 0x0c, 0x00, 0x00, 0x02,
0x00, 0x04, 0x04, 0x07, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
}
d.SendCommand(LUT_VCOM)
for i := 0; i < 44; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x04, 0x04, 0x07, 0x00, 0x01,
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
0xa8, 0x04, 0x04, 0x07, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x04, 0x04, 0x07, 0x00, 0x01,
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
0xa8, 0x04, 0x04, 0x07, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x04, 0x04, 0x07, 0x00, 0x01,
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
0x54, 0x04, 0x04, 0x07, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x04, 0x04, 0x07, 0x00, 0x01,
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
0x54, 0x04, 0x04, 0x07, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
break
case TURBO:
var lut = [44]uint8{
0x00, 0x01, 0x01, 0x02, 0x00, 0x01,
0x00, 0x02, 0x02, 0x00, 0x00, 0x02,
0x00, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
}
d.SendCommand(LUT_VCOM)
for i := 0; i < 44; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0xa8, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0xa8, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0x54, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0x54, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
break
default:
var lut = [44]uint8{
0x00, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x8c, 0x8c, 0x00, 0x00, 0x04,
0x00, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
}
d.SendCommand(LUT_VCOM)
for i := 0; i < 44; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BW)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_WB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
lut = [44]uint8{
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
d.SendCommand(LUT_BB)
// do not send last two bytes
for i := 0; i < 42; i++ {
d.SendData(lut[i])
}
break
}
}
+1 -1
View File
@@ -2,4 +2,4 @@ package drivers
// Version returns a user-readable string showing the version of the drivers package for support purposes.
// Update this value before release of new version of software.
const Version = "0.20.0"
const Version = "0.21.0"
+1
View File
@@ -7,6 +7,7 @@ const Address = 0x29 //0x52
const (
CHIP_ID = 0xEACC
SOFT_RESET = 0x0000
I2C_SLAVE_DEVICE_ADDRESS = 0x0001
OSC_MEASURED_FAST_OSC_FREQUENCY = 0x0006
VHV_CONFIG_TIMEOUT_MACROP_LOOP_BOUND = 0x0008
VHV_CONFIG_INIT = 0x000B
+11
View File
@@ -133,6 +133,17 @@ func (d *Device) Configure(use2v8Mode bool) bool {
return true
}
// SetAddress sets the I2C address which this device listens to.
func (d *Device) SetAddress(address uint8) {
d.writeReg(I2C_SLAVE_DEVICE_ADDRESS, address)
d.Address = uint16(address)
}
// GetAddress returns the I2C address which this device listens to.
func (d *Device) GetAddress() uint8 {
return uint8(d.Address)
}
// SetTimeout configures the timeout
func (d *Device) SetTimeout(timeout uint32) {
d.timeout = timeout
+23
View File
@@ -12,6 +12,7 @@ import (
"fmt" // used only in debug printouts and is optimized out when debugging is disabled
"strconv"
"strings"
"sync"
"time"
"machine"
@@ -288,6 +289,7 @@ type Device struct {
proto uint8
ip uint32
port uint16
mu sync.Mutex
}
// New returns a new Wifinina device.
@@ -363,6 +365,9 @@ func (d *Device) GetClientState(sock uint8) (uint8, error) {
}
func (d *Device) SendData(buf []byte, sock uint8) (uint16, error) {
d.mu.Lock()
defer d.mu.Unlock()
if err := d.waitForChipSelect(); err != nil {
d.spiChipDeselect()
return 0, err
@@ -376,6 +381,9 @@ func (d *Device) SendData(buf []byte, sock uint8) (uint16, error) {
}
func (d *Device) CheckDataSent(sock uint8) (bool, error) {
d.mu.Lock()
defer d.mu.Unlock()
var lastErr error
for timeout := 0; timeout < 10; timeout++ {
sent, err := d.getUint8(d.reqUint8(CmdDataSentTCP, sock))
@@ -391,6 +399,9 @@ func (d *Device) CheckDataSent(sock uint8) (bool, error) {
}
func (d *Device) GetDataBuf(sock uint8, buf []byte) (int, error) {
d.mu.Lock()
defer d.mu.Unlock()
if err := d.waitForChipSelect(); err != nil {
d.spiChipDeselect()
return 0, err
@@ -411,6 +422,9 @@ func (d *Device) GetDataBuf(sock uint8, buf []byte) (int, error) {
}
func (d *Device) StopClient(sock uint8) error {
d.mu.Lock()
defer d.mu.Unlock()
if _debug {
println("[StopClient] called StopClient()\r")
}
@@ -419,6 +433,9 @@ func (d *Device) StopClient(sock uint8) error {
}
func (d *Device) StartServer(port uint16, sock uint8, mode uint8) error {
d.mu.Lock()
defer d.mu.Unlock()
if err := d.waitForChipSelect(); err != nil {
d.spiChipDeselect()
return err
@@ -435,6 +452,9 @@ func (d *Device) StartServer(port uint16, sock uint8, mode uint8) error {
// InsertDataBuf adds data to the buffer used for sending UDP data
func (d *Device) InsertDataBuf(buf []byte, sock uint8) (bool, error) {
d.mu.Lock()
defer d.mu.Unlock()
if err := d.waitForChipSelect(); err != nil {
d.spiChipDeselect()
return false, err
@@ -450,6 +470,9 @@ func (d *Device) InsertDataBuf(buf []byte, sock uint8) (bool, error) {
// SendUDPData sends the data previously added to the UDP buffer
func (d *Device) SendUDPData(sock uint8) (bool, error) {
d.mu.Lock()
defer d.mu.Unlock()
if err := d.waitForChipSelect(); err != nil {
d.spiChipDeselect()
return false, err
+2 -1
View File
@@ -252,7 +252,7 @@ func writeGoWrapper(f *os.File, arch string, megahertz int) error {
fmt.Fprintf(buf, " portClear, maskClear := d.Pin.PortMaskClear()\n")
fmt.Fprintf(buf, "\n")
fmt.Fprintf(buf, " mask := interrupt.Disable()\n")
fmt.Fprintf(buf, " C.ws2812_writeByte%d(C.char(c), portSet, portClear, maskSet, maskClear)\n", megahertz)
fmt.Fprintf(buf, " C.ws2812_writeByte%d(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)\n", megahertz)
buf.WriteString(`
interrupt.Restore(mask)
}
@@ -293,6 +293,7 @@ package ws2812
// gen-ws2812.go and run "go generate".
import "runtime/interrupt"
import "unsafe"
/*
#include <stdint.h>
+311 -5
View File
@@ -7,6 +7,7 @@ package ws2812
// gen-ws2812.go and run "go generate".
import "runtime/interrupt"
import "unsafe"
/*
#include <stdint.h>
@@ -636,6 +637,301 @@ void ws2812_writeByte120(char c, uint32_t *portSet, uint32_t *portClear, uint32_
[portClear]"m"(*portClear));
}
__attribute__((always_inline))
void ws2812_writeByte125(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
// Timings:
// T0H: 44 - 46 cycles or 352.0ns - 368.0ns
// T1H: 132 - 134 cycles or 1056.0ns - 1072.0ns
// TLD: 144 - cycles or 1152.0ns -
uint32_t value = (uint32_t)c << 24;
char i = 8;
__asm__ __volatile__(
"1: @ send_bit\n"
"\t str %[maskSet], %[portSet] @ [2] T0H and T0L start here\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t lsls %[value], #1 @ [1]\n"
"\t bcs.n 2f @ [1/3] skip_store\n"
"\t str %[maskClear], %[portClear] @ [2] T0H -> T0L transition\n"
"\t2: @ skip_store\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t str %[maskClear], %[portClear] @ [2] T1H -> T1L transition\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t nop\n"
"\t subs %[i], #1 @ [1]\n"
"\t beq.n 3f @ [1/3] end\n"
"\t b 1b @ [1/3] send_bit\n"
"\t3: @ end\n"
: [value]"+r"(value),
[i]"+r"(i)
: [maskSet]"r"(maskSet),
[portSet]"m"(*portSet),
[maskClear]"r"(maskClear),
[portClear]"m"(*portClear));
}
__attribute__((always_inline))
void ws2812_writeByte168(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) {
// Timings:
@@ -1033,7 +1329,7 @@ func (d Device) writeByte16(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte16(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte16(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
@@ -1043,7 +1339,7 @@ func (d Device) writeByte48(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte48(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte48(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
@@ -1053,7 +1349,7 @@ func (d Device) writeByte64(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte64(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte64(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
@@ -1063,7 +1359,17 @@ func (d Device) writeByte120(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte120(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte120(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
func (d Device) writeByte125(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte125(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
@@ -1073,7 +1379,7 @@ func (d Device) writeByte168(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte168(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte168(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
+3 -2
View File
@@ -7,6 +7,7 @@ package ws2812
// gen-ws2812.go and run "go generate".
import "runtime/interrupt"
import "unsafe"
/*
#include <stdint.h>
@@ -1114,7 +1115,7 @@ func (d Device) writeByte160(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte160(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte160(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
@@ -1124,7 +1125,7 @@ func (d Device) writeByte320(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
mask := interrupt.Disable()
C.ws2812_writeByte320(C.char(c), portSet, portClear, maskSet, maskClear)
C.ws2812_writeByte320(C.char(c), (*uint32)(unsafe.Pointer(portSet)), (*uint32)(unsafe.Pointer(portClear)), maskSet, maskClear)
interrupt.Restore(mask)
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
package ws2812 // import "tinygo.org/x/drivers/ws2812"
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 168
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
import (
+3
View File
@@ -29,6 +29,9 @@ func (d Device) WriteByte(c byte) error {
case 120_000_000: // 120MHz
d.writeByte120(c)
return nil
case 125_000_000: // 125 MHz e.g. rp2040
d.writeByte125(c)
return nil
case 168_000_000: // 168MHz, e.g. stm32f405
d.writeByte168(c)
return nil