mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-27 02:58:41 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90a13a697b | |||
| d632eb888f | |||
| f6761a9079 | |||
| 51c3aa271b | |||
| 520234e9f8 | |||
| 334ed57373 | |||
| 3637033fec | |||
| 233866443c | |||
| 65fd7aa1a1 | |||
| 82e9e4a7f3 | |||
| 76ff632134 | |||
| cd2694e85f | |||
| 734adb6df8 | |||
| 2492fcb322 | |||
| 4f82c231cb | |||
| 2c9a05a413 | |||
| a89a26112e | |||
| bd42656644 | |||
| 94729a4f7d | |||
| 050cf4dbbc | |||
| 49c8810432 | |||
| 4b38841f71 |
@@ -1,3 +0,0 @@
|
||||
[submodule "espnet/esp-idf"]
|
||||
path = espnet/esp-idf
|
||||
url = https://github.com/espressif/esp-idf.git
|
||||
@@ -1,3 +1,35 @@
|
||||
0.18.0
|
||||
---
|
||||
- **new devices**
|
||||
- apds9960: add support for APDS-9960 Digital Proximity sensor
|
||||
- axp192: add support for AXP192 single Cell Li-Battery and power system management IC
|
||||
- hts221: add support for HTS221 capacitive digital sensor for relative humidity and temperature
|
||||
- i2csoft: add support for software I2C
|
||||
- image: add support for image/jpeg and image/png
|
||||
- lps22hb: add support for LPS22HB MEMS nano pressure sensor
|
||||
- lsm6dox: add support for lsm6dox accelerometer
|
||||
- lsm9ds1: add support for lsm9ds1 accelerometer
|
||||
- **enhancements**
|
||||
- ili9341: change to use drivers.SPI interface
|
||||
- **ws2812**
|
||||
- generate assembly instead of handwriting it
|
||||
- improve timings to be compatible with the WS2811
|
||||
- add support for 168MHz (e.g. Adafruit Feather STM32F405)
|
||||
- add support for RISC-V
|
||||
- wifinina: control nina pins, for example leds
|
||||
- **docs**
|
||||
- rtl8720dn: examples for tcpclient, udpstation, mqtt, and webserver
|
||||
- **wifinina**
|
||||
- nina-fw update docs
|
||||
- examples/wifinina/http-get
|
||||
- ili9341: refactor examples
|
||||
- Fix broken link for SHT3x datasheet
|
||||
- **core**
|
||||
- all: use build directives for both Go1.17 and earlier versions
|
||||
- **bugfixes**
|
||||
- net: fix raddr of tcp conn
|
||||
- mcp3008: fix bitshift bug
|
||||
|
||||
0.17.1
|
||||
---
|
||||
- To correct an error in the release process. Same as 0.17.0.
|
||||
|
||||
@@ -17,6 +17,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
|
||||
@@ -63,6 +65,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/hd44780i2c/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/hts221/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hub75/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic
|
||||
@@ -79,6 +83,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
|
||||
@@ -205,12 +211,16 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/mqttsub/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
|
||||
@md5sum ./build/test.hex
|
||||
|
||||
DRIVERS = $(wildcard */)
|
||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd
|
||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192
|
||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||
|
||||
unit-test:
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 67 devices are supported.
|
||||
The following 74 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|----------|-------------|
|
||||
@@ -61,7 +61,9 @@ The following 67 devices are supported.
|
||||
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
|
||||
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
|
||||
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
|
||||
| [APDS9960 Digital proximity, ambient light, RGB and gesture sensor](https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf) | I2C |
|
||||
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
|
||||
| [AXP192 single Cell Li-Battery and Power System Management](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf) | I2C |
|
||||
| [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO |
|
||||
| [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C |
|
||||
| [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C |
|
||||
@@ -79,7 +81,9 @@ The following 67 devices are supported.
|
||||
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
|
||||
| [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO |
|
||||
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
|
||||
| [HTS221 digital humidity and temperature sensor](https://www.st.com/resource/en/datasheet/hts221.pdf) | I2C |
|
||||
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
|
||||
| [software I2C driver](https://www.ti.com/lit/an/slva704/slva704.pdf) | GPIO |
|
||||
| [ILI9341 TFT color display](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) | SPI |
|
||||
| [INA260 Volt/Amp/Power meter](https://www.ti.com/lit/ds/symlink/ina260.pdf) | I2C |
|
||||
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
|
||||
@@ -87,12 +91,16 @@ The following 67 devices are supported.
|
||||
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
|
||||
| [LIS2MDL magnetometer](https://www.st.com/resource/en/datasheet/lis2mdl.pdf) | I2C |
|
||||
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
|
||||
| [LPS22HB MEMS nano pressure sensor](https://www.st.com/resource/en/datasheet/dm00140895.pdf) | I2C |
|
||||
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C |
|
||||
| [LSM6DSOX accelerometer](https://www.st.com/resource/en/datasheet/lsm6dsox.pdf) | I2C |
|
||||
| [LSM303AGR accelerometer](https://www.st.com/resource/en/datasheet/lsm303agr.pdf) | I2C |
|
||||
| [LSM9DS1 accelerometer](https://www.st.com/resource/en/datasheet/lsm9ds1.pdf) | I2C |
|
||||
| [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C |
|
||||
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
|
||||
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
||||
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
||||
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
|
||||
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
||||
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
||||
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
|
||||
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
|
||||
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
||||
@@ -105,7 +113,7 @@ The following 67 devices are supported.
|
||||
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
|
||||
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
|
||||
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
||||
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
|
||||
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
// Package apds9960 implements a driver for APDS-9960,
|
||||
// a digital proximity, ambient light, RGB and gesture sensor.
|
||||
//
|
||||
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
|
||||
//
|
||||
package apds9960
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a APDS-9960 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
mode uint8
|
||||
gesture gestureData
|
||||
}
|
||||
|
||||
// Configuration for APDS-9960 device.
|
||||
type Configuration struct {
|
||||
ProximityPulseLength uint8
|
||||
ProximityPulseCount uint8
|
||||
GesturePulseLength uint8
|
||||
GesturePulseCount uint8
|
||||
ProximityGain uint8
|
||||
GestureGain uint8
|
||||
ColorGain uint8
|
||||
ADCIntegrationCycles uint16
|
||||
LEDBoost uint16
|
||||
threshold uint8
|
||||
sensitivity uint8
|
||||
}
|
||||
|
||||
// for gesture-related data
|
||||
type gestureData struct {
|
||||
detected uint8
|
||||
threshold uint8
|
||||
sensitivity uint8
|
||||
gXDelta int16
|
||||
gYDelta int16
|
||||
gXPrevDelta int16
|
||||
gYPrevDelta int16
|
||||
received bool
|
||||
}
|
||||
|
||||
// for enabling various device function
|
||||
type enableConfig struct {
|
||||
GEN bool
|
||||
PIEN bool
|
||||
AIEN bool
|
||||
WEN bool
|
||||
PEN bool
|
||||
AEN bool
|
||||
PON bool
|
||||
}
|
||||
|
||||
// Connected returns whether APDS-9960 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
|
||||
return data[0] == 0xAB
|
||||
}
|
||||
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
d.DisableAll() // turn off everything
|
||||
|
||||
// "default" settings
|
||||
if cfg.ProximityPulseLength == 0 {
|
||||
cfg.ProximityPulseLength = 16
|
||||
}
|
||||
if cfg.ProximityPulseCount == 0 {
|
||||
cfg.ProximityPulseCount = 64
|
||||
}
|
||||
if cfg.GesturePulseLength == 0 {
|
||||
cfg.GesturePulseLength = 16
|
||||
}
|
||||
if cfg.GesturePulseCount == 0 {
|
||||
cfg.GesturePulseCount = 64
|
||||
}
|
||||
if cfg.ProximityGain == 0 {
|
||||
cfg.ProximityGain = 1
|
||||
}
|
||||
if cfg.GestureGain == 0 {
|
||||
cfg.GestureGain = 1
|
||||
}
|
||||
if cfg.ColorGain == 0 {
|
||||
cfg.ColorGain = 4
|
||||
}
|
||||
if cfg.ADCIntegrationCycles == 0 {
|
||||
cfg.ADCIntegrationCycles = 4
|
||||
}
|
||||
if cfg.threshold == 0 {
|
||||
d.gesture.threshold = 30
|
||||
}
|
||||
if cfg.sensitivity == 0 {
|
||||
d.gesture.sensitivity = 20
|
||||
}
|
||||
|
||||
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
|
||||
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
|
||||
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
|
||||
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
|
||||
|
||||
if cfg.LEDBoost > 0 {
|
||||
d.LEDBoost(cfg.LEDBoost)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMode returns current engine mode
|
||||
func (d *Device) GetMode() uint8 {
|
||||
return d.mode
|
||||
}
|
||||
|
||||
// DisableAll turns off the device and all functions
|
||||
func (d *Device) DisableAll() {
|
||||
d.enable(enableConfig{})
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
|
||||
d.mode = MODE_NONE
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
}
|
||||
|
||||
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
|
||||
// default: 16, 64
|
||||
func (d *Device) SetProximityPulse(length, count uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||
}
|
||||
|
||||
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
|
||||
// default: 16, 64
|
||||
func (d *Device) SetGesturePulse(length, count uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||
}
|
||||
|
||||
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
|
||||
// default: 4 (~10 ms)
|
||||
func (d *Device) SetADCIntegrationCycles(cycles uint16) {
|
||||
if cycles > 256 {
|
||||
cycles = 256
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
|
||||
}
|
||||
|
||||
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
|
||||
// default: 1, 1, 4
|
||||
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
|
||||
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
|
||||
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
|
||||
}
|
||||
|
||||
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
|
||||
// default: 100
|
||||
func (d *Device) LEDBoost(percent uint16) {
|
||||
var v uint8
|
||||
switch percent {
|
||||
case 100:
|
||||
v = 0
|
||||
case 150:
|
||||
v = 1
|
||||
case 200:
|
||||
v = 2
|
||||
case 300:
|
||||
v = 3
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
|
||||
}
|
||||
|
||||
// Setthreshold sets threshold (0~255) for detecting gestures
|
||||
// default: 30
|
||||
func (d *Device) Setthreshold(t uint8) {
|
||||
d.gesture.threshold = t
|
||||
}
|
||||
|
||||
// Setsensitivity sets sensivity (0~100) for detecting gestures
|
||||
// default: 20
|
||||
func (d *Device) Setsensitivity(s uint8) {
|
||||
if s > 100 {
|
||||
s = 100
|
||||
}
|
||||
d.gesture.sensitivity = 100 - s
|
||||
}
|
||||
|
||||
// EnableProximity starts the proximity engine
|
||||
func (d *Device) EnableProximity() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, PEN: true, WEN: true})
|
||||
d.mode = MODE_PROXIMITY
|
||||
}
|
||||
|
||||
// ProximityAvailable reports if proximity data is available
|
||||
func (d *Device) ProximityAvailable() bool {
|
||||
if d.mode == MODE_PROXIMITY && d.readStatus("PVALID") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadProximity reads proximity data (0~255)
|
||||
func (d *Device) ReadProximity() (proximity int32) {
|
||||
if d.mode != MODE_PROXIMITY {
|
||||
return 0
|
||||
}
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
|
||||
return 255 - int32(data[0])
|
||||
}
|
||||
|
||||
// EnableColor starts the color engine
|
||||
func (d *Device) EnableColor() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, AEN: true, WEN: true})
|
||||
d.mode = MODE_COLOR
|
||||
}
|
||||
|
||||
// ColorAvailable reports if color data is available
|
||||
func (d *Device) ColorAvailable() bool {
|
||||
if d.mode == MODE_COLOR && d.readStatus("AVALID") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadColor reads color data (red, green, blue, clear color/brightness)
|
||||
func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
|
||||
if d.mode != MODE_COLOR {
|
||||
return
|
||||
}
|
||||
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
|
||||
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
|
||||
r = int32(uint16(data[3])<<8 | uint16(data[2]))
|
||||
g = int32(uint16(data[5])<<8 | uint16(data[4]))
|
||||
b = int32(uint16(data[7])<<8 | uint16(data[6]))
|
||||
return
|
||||
}
|
||||
|
||||
// EnableGesture starts the gesture engine
|
||||
func (d *Device) EnableGesture() {
|
||||
if d.mode != MODE_NONE {
|
||||
d.DisableAll()
|
||||
}
|
||||
d.enable(enableConfig{PON: true, PEN: true, GEN: true, WEN: true})
|
||||
d.mode = MODE_GESTURE
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
d.gesture.gXDelta = 0
|
||||
d.gesture.gYDelta = 0
|
||||
d.gesture.gXPrevDelta = 0
|
||||
d.gesture.gYPrevDelta = 0
|
||||
d.gesture.received = false
|
||||
}
|
||||
|
||||
// GestureAvailable reports if gesture data is available
|
||||
func (d *Device) GestureAvailable() bool {
|
||||
if d.mode != MODE_GESTURE {
|
||||
return false
|
||||
}
|
||||
|
||||
data := []byte{0, 0, 0, 0}
|
||||
|
||||
// check GVALID
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
|
||||
if data[0]&0x01 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// get number of data sets available in FIFO
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
|
||||
availableDataSets := data[0]
|
||||
if availableDataSets == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// read up, down, left and right proximity data from FIFO
|
||||
var dataSets [32][4]uint8
|
||||
for i := uint8(0); i < availableDataSets; i++ {
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
|
||||
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
|
||||
for j := uint8(0); j < 4; j++ {
|
||||
dataSets[i][j] = data[j]
|
||||
}
|
||||
}
|
||||
|
||||
// gesture detection process
|
||||
d.gesture.detected = GESTURE_NONE
|
||||
for i := uint8(0); i < availableDataSets; i++ {
|
||||
U := dataSets[i][0]
|
||||
D := dataSets[i][1]
|
||||
L := dataSets[i][2]
|
||||
R := dataSets[i][3]
|
||||
|
||||
// if all readings fall below threshold, it's possible that
|
||||
// a movement's just been made
|
||||
if U < d.gesture.threshold && D < d.gesture.threshold && L < d.gesture.threshold && R < d.gesture.threshold {
|
||||
d.gesture.received = true
|
||||
// if there were movement in the previous step (including the last data sets)
|
||||
if d.gesture.gXPrevDelta != 0 && d.gesture.gYPrevDelta != 0 {
|
||||
totalX := d.gesture.gXPrevDelta - d.gesture.gXDelta
|
||||
totalY := d.gesture.gYPrevDelta - d.gesture.gYDelta
|
||||
// if previous and current movement are in opposite directions (pass through one led then next)
|
||||
// and the difference is big enough, the gesture is recorded
|
||||
switch {
|
||||
case totalX < -int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_LEFT
|
||||
case totalX > int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_RIGHT
|
||||
case totalY > int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_DOWN
|
||||
case totalY < -int16(d.gesture.sensitivity):
|
||||
d.gesture.detected = GESTURE_UP
|
||||
}
|
||||
d.gesture.gXDelta = 0
|
||||
d.gesture.gYDelta = 0
|
||||
d.gesture.gXPrevDelta = 0
|
||||
d.gesture.gYPrevDelta = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// recording current movement
|
||||
d.gesture.gXDelta = int16(R) - int16(L)
|
||||
d.gesture.gYDelta = int16(D) - int16(U)
|
||||
if d.gesture.received {
|
||||
d.gesture.received = false
|
||||
d.gesture.gXPrevDelta = d.gesture.gXDelta
|
||||
d.gesture.gYPrevDelta = d.gesture.gYDelta
|
||||
}
|
||||
}
|
||||
|
||||
return d.gesture.detected != GESTURE_NONE
|
||||
}
|
||||
|
||||
// ReadGesture reads last gesture data
|
||||
func (d *Device) ReadGesture() (gesture int32) {
|
||||
return int32(d.gesture.detected)
|
||||
}
|
||||
|
||||
// private functions
|
||||
|
||||
func (d *Device) enable(cfg enableConfig) {
|
||||
var gen, pien, aien, wen, pen, aen, pon uint8
|
||||
|
||||
if cfg.GEN {
|
||||
gen = 1
|
||||
}
|
||||
if cfg.PIEN {
|
||||
pien = 1
|
||||
}
|
||||
if cfg.AIEN {
|
||||
aien = 1
|
||||
}
|
||||
if cfg.WEN {
|
||||
wen = 1
|
||||
}
|
||||
if cfg.PEN {
|
||||
pen = 1
|
||||
}
|
||||
if cfg.AEN {
|
||||
aen = 1
|
||||
}
|
||||
if cfg.PON {
|
||||
pon = 1
|
||||
}
|
||||
|
||||
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
|
||||
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
|
||||
|
||||
if cfg.PON {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) readStatus(param string) bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
|
||||
|
||||
switch param {
|
||||
case "CPSAT":
|
||||
return data[0]>>7&0x01 == 1
|
||||
case "PGSAT":
|
||||
return data[0]>>6&0x01 == 1
|
||||
case "PINT":
|
||||
return data[0]>>5&0x01 == 1
|
||||
case "AINT":
|
||||
return data[0]>>4&0x01 == 1
|
||||
case "PVALID":
|
||||
return data[0]>>1&0x01 == 1
|
||||
case "AVALID":
|
||||
return data[0]&0x01 == 1
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func getPulseLength(l uint8) uint8 {
|
||||
switch l {
|
||||
case 4:
|
||||
return 0
|
||||
case 8:
|
||||
return 1
|
||||
case 16:
|
||||
return 2
|
||||
case 32:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getPulseCount(c uint8) uint8 {
|
||||
if c < 1 && c > 64 {
|
||||
return 0
|
||||
}
|
||||
return c - 1
|
||||
}
|
||||
|
||||
func getProximityGain(g uint8) uint8 {
|
||||
switch g {
|
||||
case 1:
|
||||
return 0
|
||||
case 2:
|
||||
return 1
|
||||
case 4:
|
||||
return 2
|
||||
case 8:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getALSGain(g uint8) uint8 {
|
||||
switch g {
|
||||
case 1:
|
||||
return 0
|
||||
case 4:
|
||||
return 1
|
||||
case 16:
|
||||
return 2
|
||||
case 64:
|
||||
return 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package apds9960
|
||||
|
||||
const (
|
||||
|
||||
// I2C address
|
||||
ADPS9960_ADDRESS = 0x39
|
||||
|
||||
// control/status registers
|
||||
APDS9960_RAM_REG = 0x00
|
||||
APDS9960_ENABLE_REG = 0x80
|
||||
APDS9960_ATIME_REG = 0x81
|
||||
APDS9960_WTIME_REG = 0x83
|
||||
APDS9960_AILTIL_REG = 0x84
|
||||
APDS9960_AILTH_REG = 0x85
|
||||
APDS9960_AIHTL_REG = 0x86
|
||||
APDS9960_AIHTH_REG = 0x87
|
||||
APDS9960_PILT_REG = 0x89
|
||||
APDS9960_PIHT_REG = 0x8B
|
||||
APDS9960_PERS_REG = 0x8C
|
||||
APDS9960_CONFIG1_REG = 0x8D
|
||||
APDS9960_PPULSE_REG = 0x8E
|
||||
APDS9960_CONTROL_REG = 0x8F
|
||||
APDS9960_CONFIG2_REG = 0x90
|
||||
APDS9960_ID_REG = 0x92
|
||||
APDS9960_STATUS_REG = 0x93
|
||||
APDS9960_CDATAL_REG = 0x94
|
||||
APDS9960_CDATAH_REG = 0x95
|
||||
APDS9960_RDATAL_REG = 0x96
|
||||
APDS9960_RDATAH_REG = 0x97
|
||||
APDS9960_GDATAL_REG = 0x98
|
||||
APDS9960_GDATAH_REG = 0x99
|
||||
APDS9960_BDATAL_REG = 0x9A
|
||||
APDS9960_BDATAH_REG = 0x9B
|
||||
APDS9960_PDATA_REG = 0x9C
|
||||
APDS9960_POFFSET_UR_REG = 0x9D
|
||||
APDS9960_POFFSET_DL_REG = 0x9E
|
||||
APDS9960_CONFIG3_REG = 0x9F
|
||||
APDS9960_GPENTH_REG = 0xA0
|
||||
APDS9960_GEXTH_REG = 0xA1
|
||||
APDS9960_GCONF1_REG = 0xA2
|
||||
APDS9960_GCONF2_REG = 0xA3
|
||||
APDS9960_GOFFSET_U_REG = 0xA4
|
||||
APDS9960_GOFFSET_D_REG = 0xA5
|
||||
APDS9960_GOFFSET_L_REG = 0xA7
|
||||
APDS9960_GOFFSET_R_REG = 0xA9
|
||||
APDS9960_GPULSE_REG = 0xA6
|
||||
APDS9960_GCONF3_REG = 0xAA
|
||||
APDS9960_GCONF4_REG = 0xAB
|
||||
APDS9960_GFLVL_REG = 0xAE
|
||||
APDS9960_GSTATUS_REG = 0xAF
|
||||
APDS9960_IFORCE_REG = 0xE4
|
||||
APDS9960_PICLEAR_REG = 0xE5
|
||||
APDS9960_CICLEAR_REG = 0xE6
|
||||
APDS9960_AICLEAR_REG = 0xE7
|
||||
APDS9960_GFIFO_U_REG = 0xFC
|
||||
APDS9960_GFIFO_D_REG = 0xFD
|
||||
APDS9960_GFIFO_L_REG = 0xFE
|
||||
APDS9960_GFIFO_R_REG = 0xFF
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// sensor modes
|
||||
MODE_NONE = iota
|
||||
MODE_PROXIMITY
|
||||
MODE_COLOR
|
||||
MODE_GESTURE
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// detected gestures
|
||||
GESTURE_NONE = iota
|
||||
GESTURE_UP
|
||||
GESTURE_DOWN
|
||||
GESTURE_LEFT
|
||||
GESTURE_RIGHT
|
||||
)
|
||||
@@ -0,0 +1,258 @@
|
||||
// Package axp192 provides a driver for the axp192 I2C Enhanced single Cell
|
||||
// Li-Battery and Power System Management IC.
|
||||
//
|
||||
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
|
||||
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
|
||||
//
|
||||
package axp192 // import "tinygo.org/x/drivers/axp192"
|
||||
|
||||
import (
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type Error uint8
|
||||
|
||||
const (
|
||||
ErrInvalidID Error = 0x1
|
||||
)
|
||||
|
||||
func (e Error) Error() string {
|
||||
switch e {
|
||||
case ErrInvalidID:
|
||||
return "Invalid chip ID"
|
||||
default:
|
||||
return "Unknown error"
|
||||
}
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
buf []byte
|
||||
Address uint8
|
||||
}
|
||||
|
||||
// New returns AXP192 device for the provided I2C bus using default address.
|
||||
func New(i2c drivers.I2C) *Device {
|
||||
return &Device{
|
||||
bus: i2c,
|
||||
buf: make([]byte, 2),
|
||||
Address: Address,
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure the AXP192 device.
|
||||
func (d *Device) Configure(config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadPowerSupplyStatus reads power supply status.
|
||||
func (d *Device) ReadPowerSupplyStatus() uint8 {
|
||||
return d.read8bit(RegPowerSupplyStatus)
|
||||
}
|
||||
|
||||
// SetVbusIPSOutAccessManagement sets VBUS-IPSOUT access management.
|
||||
func (d *Device) SetVbusIPSOutAccessManagement(a uint8) {
|
||||
d.write1Byte(RegVbusIPSOutAccessManagement, a)
|
||||
}
|
||||
|
||||
// GetVbusIPSOutAccessManagement gets VBUS-IPSOUT access management.
|
||||
func (d *Device) GetVbusIPSOutAccessManagement() uint8 {
|
||||
return d.read8bit(RegVbusIPSOutAccessManagement)
|
||||
}
|
||||
|
||||
// SetGPIO1Control sets GPIO1 function.
|
||||
func (d *Device) SetGPIO1Control(a uint8) {
|
||||
d.write1Byte(RegGPIO1Control, a)
|
||||
}
|
||||
|
||||
// GetGPIO1Control gets GPIO1 function.
|
||||
func (d *Device) GetGPIO1Control() uint8 {
|
||||
return d.read8bit(RegGPIO1Control)
|
||||
}
|
||||
|
||||
// SetGPIO2Control sets GPIO2 function.
|
||||
func (d *Device) SetGPIO2Control(a uint8) {
|
||||
d.write1Byte(RegGPIO2Control, a)
|
||||
}
|
||||
|
||||
// GetGPIO2Control gets GPIO2 function.
|
||||
func (d *Device) GetGPIO2Control() uint8 {
|
||||
return d.read8bit(RegGPIO2Control)
|
||||
}
|
||||
|
||||
// SetGPIO20SignalStatus sets GPIO[2:0] signal status.
|
||||
func (d *Device) SetGPIO20SignalStatus(a uint8) {
|
||||
d.write1Byte(RegGPIO20SignalStatus, a)
|
||||
}
|
||||
|
||||
// GetGPIO20SignalStatus gets GPIO[2:0] signal status.
|
||||
func (d *Device) GetGPIO20SignalStatus() uint8 {
|
||||
return d.read8bit(RegGPIO20SignalStatus)
|
||||
}
|
||||
|
||||
// SetBackupBatteryChargingControl sets backup battery charge control.
|
||||
func (d *Device) SetBackupBatteryChargingControl(a uint8) {
|
||||
d.write1Byte(RegBackupBatteryChargingControl, a)
|
||||
}
|
||||
|
||||
// GetBackupBatteryChargingControl gets backup battery charge control.
|
||||
func (d *Device) GetBackupBatteryChargingControl() uint8 {
|
||||
return d.read8bit(RegBackupBatteryChargingControl)
|
||||
}
|
||||
|
||||
// SetDCDC1VoltageSet sets DC-DC1 output voltage.
|
||||
func (d *Device) SetDCDC1VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC1VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC1VoltageSet gets DC-DC1 output voltage.
|
||||
func (d *Device) GetDCDC1VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC1VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC2VoltageSet sets DC-DC2 dynamic voltage parameter.
|
||||
func (d *Device) SetDCDC2VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC2VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC2VoltageSet gets DC-DC2 dynamic voltage parameter.
|
||||
func (d *Device) GetDCDC2VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC2VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC3VoltageSet sets DC-DC3 output voltage.
|
||||
func (d *Device) SetDCDC3VoltageSet(a uint8) {
|
||||
d.write1Byte(RegDCDC3VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetDCDC3VoltageSet gets DC-DC3 output voltage.
|
||||
func (d *Device) GetDCDC3VoltageSet() uint8 {
|
||||
return d.read8bit(RegDCDC3VoltageSet)
|
||||
}
|
||||
|
||||
// SetLDO23VoltageSet sets LDO2/3 output voltage.
|
||||
func (d *Device) SetLDO23VoltageSet(a uint8) {
|
||||
d.write1Byte(RegLDO23VoltageSet, a)
|
||||
}
|
||||
|
||||
// GetLDO23VoltageSet gets LDO2/3 output voltage.
|
||||
func (d *Device) GetLDO23VoltageSet() uint8 {
|
||||
return d.read8bit(RegLDO23VoltageSet)
|
||||
}
|
||||
|
||||
// SetDCDC13LDO23Switch sets DC-DC1/3 & LOD2/3 output control.
|
||||
func (d *Device) SetDCDC13LDO23Switch(a uint8) {
|
||||
d.write1Byte(RegDCDC13LDO23Switch, a)
|
||||
}
|
||||
|
||||
// GetDCDC13LDO23Switch gets DC-DC1/3 & LOD2/3 output control.
|
||||
func (d *Device) GetDCDC13LDO23Switch() uint8 {
|
||||
return d.read8bit(RegDCDC13LDO23Switch)
|
||||
}
|
||||
|
||||
// SetGPIO43FunctionControl sets GPIO[4:3] pin function.
|
||||
func (d *Device) SetGPIO43FunctionControl(a uint8) {
|
||||
d.write1Byte(RegGPIO43FunctionControl, a)
|
||||
}
|
||||
|
||||
// GetGPIO43FunctionControl gets GPIO[4:3] pin function.
|
||||
func (d *Device) GetGPIO43FunctionControl() uint8 {
|
||||
return d.read8bit(RegGPIO43FunctionControl)
|
||||
}
|
||||
|
||||
// SetPEKParameterSet sets PEK press key parameter.
|
||||
func (d *Device) SetPEKParameterSet(a uint8) {
|
||||
d.write1Byte(RegPEKParameterSet, a)
|
||||
}
|
||||
|
||||
// GetPEKParameterSet gets PEK press key parameter.
|
||||
func (d *Device) GetPEKParameterSet() uint8 {
|
||||
return d.read8bit(RegPEKParameterSet)
|
||||
}
|
||||
|
||||
// SetADCEnableSet sets ADC enable 1.
|
||||
func (d *Device) SetADCEnableSet(a uint8) {
|
||||
d.write1Byte(RegADCEnableSet, a)
|
||||
}
|
||||
|
||||
// GetADCEnableSet gets ADC enable 1.
|
||||
func (d *Device) GetADCEnableSet() uint8 {
|
||||
return d.read8bit(RegADCEnableSet)
|
||||
}
|
||||
|
||||
// SetGPIO43SignalStatus sets GPIO[4:3] signal status.
|
||||
func (d *Device) SetGPIO43SignalStatus(a uint8) {
|
||||
d.write1Byte(RegGPIO43SignalStatus, a)
|
||||
}
|
||||
|
||||
// GetGPIO43SignalStatus gets GPIO[4:3] signal status.
|
||||
func (d *Device) GetGPIO43SignalStatus() uint8 {
|
||||
return d.read8bit(RegGPIO43SignalStatus)
|
||||
}
|
||||
|
||||
// SetDCVoltage sets DC voltage.
|
||||
func (d *Device) SetDCVoltage(number uint8, voltage uint16) {
|
||||
if voltage < 700 {
|
||||
voltage = 0
|
||||
} else {
|
||||
voltage = (voltage - 700) / 25
|
||||
}
|
||||
|
||||
switch number {
|
||||
case 0:
|
||||
v := d.GetDCDC1VoltageSet()
|
||||
d.SetDCDC1VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
case 1:
|
||||
v := d.GetDCDC2VoltageSet()
|
||||
d.SetDCDC2VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
case 2:
|
||||
v := d.GetDCDC3VoltageSet()
|
||||
d.SetDCDC3VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F))
|
||||
}
|
||||
}
|
||||
|
||||
// SetLDOVoltage sets LDO voltage.
|
||||
func (d *Device) SetLDOVoltage(number uint8, voltage uint16) {
|
||||
if voltage > 3300 {
|
||||
voltage = 15
|
||||
} else {
|
||||
voltage = (voltage / 100) - 18
|
||||
}
|
||||
|
||||
switch number {
|
||||
case 2:
|
||||
v := d.GetLDO23VoltageSet()
|
||||
d.SetLDO23VoltageSet((v & 0x0F) | (uint8(voltage) << 4))
|
||||
break
|
||||
case 3:
|
||||
v := d.GetLDO23VoltageSet()
|
||||
d.SetLDO23VoltageSet((v & 0xF0) | uint8(voltage))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// SetLDOEnable enable LDO.
|
||||
func (d *Device) SetLDOEnable(number uint8, state bool) {
|
||||
mark := uint8(0x01)
|
||||
mark <<= number
|
||||
switch number {
|
||||
case 2:
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
d.SetDCDC13LDO23Switch(v | mark)
|
||||
case 3:
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
d.SetDCDC13LDO23Switch(v & (^mark))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) write1Byte(reg, data uint8) {
|
||||
d.bus.WriteRegister(d.Address, reg, []byte{data})
|
||||
}
|
||||
|
||||
func (d *Device) read8bit(reg uint8) uint8 {
|
||||
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
|
||||
return d.buf[0]
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package axp192
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
axp192orig "tinygo.org/x/drivers/axp192"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a AXP192 device.
|
||||
type Device struct {
|
||||
*axp192orig.Device
|
||||
LED Pin
|
||||
RST Pin
|
||||
SPK_EN Pin
|
||||
}
|
||||
|
||||
// New creates a new AXP192 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(i2c drivers.I2C) *Device {
|
||||
d := axp192orig.New(i2c)
|
||||
|
||||
axp := &Device{
|
||||
Device: d,
|
||||
}
|
||||
axp.LED = Pin{pin: 1, axp: axp}
|
||||
axp.SPK_EN = Pin{pin: 2, axp: axp}
|
||||
axp.RST = Pin{pin: 4, axp: axp}
|
||||
|
||||
axp.begin()
|
||||
|
||||
return axp
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication
|
||||
func (d *Device) Configure(config Config) error {
|
||||
return d.Device.Configure(axp192orig.Config{})
|
||||
}
|
||||
|
||||
func (d *Device) begin() {
|
||||
d.SetVbusIPSOutAccessManagement((d.GetVbusIPSOutAccessManagement() & 0x04) | 0x02)
|
||||
d.SetGPIO1Control(d.GetGPIO1Control() & 0xF8)
|
||||
d.SetGPIO2Control(d.GetGPIO2Control() & 0xF8)
|
||||
d.SetBackupBatteryChargingControl((d.GetBackupBatteryChargingControl() & 0x1C) | 0xA2)
|
||||
d.SetESPVoltage(3350)
|
||||
d.SetLcdVoltage(3300)
|
||||
d.SetLDOVoltage(2, 3300) //Periph power voltage preset (LCD_logic, SD card)
|
||||
d.SetLDOVoltage(3, 2000) //Vibrator power voltage preset
|
||||
|
||||
d.SetLDOEnable(2, true)
|
||||
d.SetDCDC3(true) // LCD Backlight
|
||||
// GPIO4 : LCD Reset
|
||||
d.SetGPIO43FunctionControl((d.GetGPIO43FunctionControl() & 0x72) | 0x84)
|
||||
// Power On/Off Setting
|
||||
d.SetPEKParameterSet(0x4C)
|
||||
d.SetADCEnableSet(0xFF)
|
||||
|
||||
d.RST.Low()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
d.RST.High()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
// ToggleLED toggles LED connected to AXP192.
|
||||
func (d *Device) ToggleLED() {
|
||||
v := d.GetGPIO20SignalStatus()
|
||||
if (v & 0x02) > 0 {
|
||||
d.SetGPIO20SignalStatus(v & 0xFD)
|
||||
} else {
|
||||
d.SetGPIO20SignalStatus(v | 0x02)
|
||||
}
|
||||
}
|
||||
|
||||
// SetESPVoltage sets voltage of ESP32.
|
||||
func (d *Device) SetESPVoltage(voltage uint16) {
|
||||
if voltage >= 3000 && voltage <= 3400 {
|
||||
d.SetDCVoltage(0, voltage)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLcdVoltage sets voltage of LCD.
|
||||
func (d *Device) SetLcdVoltage(voltage uint16) {
|
||||
if voltage >= 2500 && voltage <= 3300 {
|
||||
d.SetDCVoltage(2, voltage)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDCDC3 enables or disables DCDC3.
|
||||
func (d *Device) SetDCDC3(State bool) {
|
||||
v := d.GetDCDC13LDO23Switch()
|
||||
if State == true {
|
||||
v = (1 << 1) | v
|
||||
} else {
|
||||
v = ^(uint8(1) << 1) & v
|
||||
}
|
||||
d.SetDCDC13LDO23Switch(v)
|
||||
}
|
||||
|
||||
// Pin is a single pin on AXP192.
|
||||
type Pin struct {
|
||||
pin uint8
|
||||
axp *Device
|
||||
}
|
||||
|
||||
// High sets this GPIO pin to high.
|
||||
func (p Pin) High() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
p.axp.SetGPIO20SignalStatus(v | 0x02)
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
v |= uint8(0x02)
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Low sets this GPIO pin to low.
|
||||
func (p Pin) Low() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
p.axp.SetGPIO20SignalStatus(v & 0xFD)
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
v &= ^uint8(0x02)
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle switches an output pin from low to high or from high to low.
|
||||
func (p Pin) Toggle() {
|
||||
switch p.pin {
|
||||
case 1: // LED
|
||||
v := p.axp.GetGPIO20SignalStatus()
|
||||
if (v & 0x02) == 0 {
|
||||
p.axp.SetGPIO20SignalStatus(v | 0x02)
|
||||
} else {
|
||||
p.axp.SetGPIO20SignalStatus(v & 0xFD)
|
||||
}
|
||||
case 2: // SPK_EN
|
||||
case 4: // RST
|
||||
v := p.axp.GetGPIO43SignalStatus()
|
||||
if (v & 0x02) == 0 {
|
||||
v |= uint8(0x02)
|
||||
} else {
|
||||
v &= ^uint8(0x02)
|
||||
}
|
||||
p.axp.SetGPIO43SignalStatus(v)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package axp192
|
||||
|
||||
// power supply control class
|
||||
// 0x00 Power supply status register
|
||||
// 0x01 Power supply mode/charging status register
|
||||
// 0x04 OTG VBUS status register
|
||||
// 0x06‐09 Data buffer register
|
||||
// 0x10 EXTEN & DC‐DC2 switch register
|
||||
// 0x12 DC‐DC1/3 & LDO2/3switch register
|
||||
// 0x23 DC‐DC2 voltage set register
|
||||
// 0x25 DC‐DC2 voltage slope set register
|
||||
// 0x26 DC‐DC1voltage set register
|
||||
// 0x27 DC‐DC3 voltage set register
|
||||
// 0x28 LDO2/3 voltage set register
|
||||
// 0x30 VBUS‐IPSOUT access set register
|
||||
// 0x31 VOFF power off voltage set register
|
||||
// 0x32 Power off、battery detect、CHGLED control register
|
||||
// 0x33 Charging control register1
|
||||
// 0x34 Charging control register2
|
||||
// 0x35 Backup battery charging control register
|
||||
// 0x36 PEK parameter set register
|
||||
// 0x37 DCDC switch frequency set register
|
||||
// 0x38 Battery charging under temperature warning set register
|
||||
// 0x39 Battery charging over temperature warning set register
|
||||
// 0x3A APS under voltage Level1 set register
|
||||
// 0x3B APS under voltage Level2 set register
|
||||
// 0x3C Battery discharging under temperature warning set register
|
||||
// 0x3D Battery discharging over temperature warning set register
|
||||
// 0x80 DCDC mode set register
|
||||
// 0x82 ADC enable set register 1
|
||||
// 0x83 ADC enable set register 2
|
||||
// 0x84 ADC sample frequency set, TS pin control register
|
||||
// 0x85 GPIO [3:0] input range set register
|
||||
// 0x8A Timer control register
|
||||
// 0x8B VBUS monitor set register
|
||||
// 0x8F Over temperature power off control register
|
||||
|
||||
// GPIO control class
|
||||
// 0x90 GPIO0 control register
|
||||
// 0x91 GPIO0 LDO mode output voltage set register
|
||||
// 0x92 GPIO1 control register
|
||||
// 0x93 GPIO2 control register
|
||||
// 0x94 GPIO[2:0] signal status register
|
||||
// 0x95 GPIO[4:3] function control register
|
||||
// 0x96 GPIO[4:3] signal status register
|
||||
// 0x97 GPIO[2:0] pull down control register
|
||||
// 0x98 PWM1 frequency set register
|
||||
// 0x99 PWM1 duty ratio set register 1
|
||||
// 0x9A PWM1 duty ratio set register 2
|
||||
// 0x9B PWM2 frequency set register
|
||||
// 0x9C PWM2 duty ratio set register 1
|
||||
// 0x9D PWM2 duty ratio set register 2
|
||||
// 0x9E GPIO5 control register
|
||||
|
||||
// IRQ control class
|
||||
// 0x40 IRQ enable control register 1
|
||||
// 0x41 IRQ enable control register 2
|
||||
// 0x42 IRQ enable control register 3
|
||||
// 0x43 IRQ enable control register 4
|
||||
// 0x44 IRQ status register 1
|
||||
// 0x45 IRQ status register 2
|
||||
// 0x46 IRQ status register 3
|
||||
// 0x47 IRQ status register 4
|
||||
|
||||
// ADC data class
|
||||
// 0x56 ACIN voltage ADC data high 8 bit
|
||||
// 0x57 ACIN voltage ADC data low 4 bit
|
||||
// 0x58 ACIN current ADC data high 8 bit
|
||||
// 0x59 ACIN current ADC data low 4 bit
|
||||
// 0x5A VBUS voltage ADC data high 8 bit
|
||||
// 0x5B VBUS voltage ADC data low 4 bit
|
||||
// 0x5C VBUS current ADC data high 8 bit
|
||||
// 0x5D VBUS current ADC data low 4 bit
|
||||
// 0x5E AXP192 internal temperature monitor ADC data High 8 bit
|
||||
// 0x5F AXP192 internal temperature monitor ADC data low 4 bit
|
||||
// 0x62 TS input ADC data High 8 bit,monitor battery temperature by default
|
||||
// 0x63 TS input ADC data low 4 bit,monitor battery temperature by default
|
||||
// 0x64 GPIO0 voltage ADC data high 8 bit
|
||||
// 0x65 GPIO0 voltage ADC data low 4 bit
|
||||
// 0x66 GPIO1 voltage ADC data high 8 bit
|
||||
// 0x67 GPIO1 voltage ADC data low 4 bit
|
||||
// 0x68 GPIO2 voltage ADC data high 8 bit
|
||||
// 0x69 GPIO2 voltage ADC data low 4 bit
|
||||
// 0x6A GPIO[3] voltage ADC data high 8 bit
|
||||
// 0x6B GPIO[3] voltage ADC data low 4 bit
|
||||
// 0x70 Battery instantaneous power high 8 bit
|
||||
// 0x71 Battery instantaneous power middle 8 bit
|
||||
// 0x72 Battery instantaneous power low 8 bit
|
||||
// 0x78 Battery voltage high 8 bit
|
||||
// 0x79 Battery voltage low 4 bit
|
||||
// 0x7A Battery charging current high 8 bit
|
||||
// 0x7B Battery charging current low 5 bit
|
||||
// 0x7C Battery discharging current high 8 bit
|
||||
// 0x7D Battery discharging current low 5 bit
|
||||
// 0x7E APS voltage high 8 bit
|
||||
// 0x7F APS voltage low 4 bit
|
||||
// 0xB0 Battery charging coulomb counter data register 3
|
||||
// 0xB1 Battery charging coulomb counter data register 2
|
||||
// 0xB2 Battery charging coulomb counter data register 1
|
||||
// 0xB3 Battery charging coulomb counter data register 0
|
||||
// 0xB4 Battery discharging coulomb counter data register 3
|
||||
// 0xB5 Battery discharging coulomb counter data register 2
|
||||
// 0xB6 Battery discharging coulomb counter data register 1
|
||||
// 0xB7 Battery discharging coulomb counter data register 0
|
||||
// 0xB8 Coulomb counter control register
|
||||
|
||||
const (
|
||||
// Address is default I2C address.
|
||||
Address = 0x34
|
||||
|
||||
RegPowerSupplyStatus = 0x00
|
||||
RegDCDC13LDO23Switch = 0x12
|
||||
RegVbusIPSOutAccessManagement = 0x30
|
||||
RegBackupBatteryChargingControl = 0x35
|
||||
RegDCDC2VoltageSet = 0x25
|
||||
RegDCDC1VoltageSet = 0x26
|
||||
RegDCDC3VoltageSet = 0x27
|
||||
RegLDO23VoltageSet = 0x28
|
||||
RegPEKParameterSet = 0x36
|
||||
RegADCEnableSet = 0x82
|
||||
|
||||
RegGPIO1Control = 0x92
|
||||
RegGPIO2Control = 0x93
|
||||
RegGPIO20SignalStatus = 0x94
|
||||
RegGPIO43FunctionControl = 0x95
|
||||
RegGPIO43SignalStatus = 0x96
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
package espnet
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DCONFIG_IDF_TARGET_ESP32C3
|
||||
#cgo CFLAGS: -Iinclude
|
||||
#cgo CFLAGS: -Iesp-idf/components/esp_common/include
|
||||
#cgo CFLAGS: -Iesp-idf/components/esp_event/include
|
||||
#cgo CFLAGS: -Iesp-idf/components/esp_netif/include
|
||||
#cgo CFLAGS: -Iesp-idf/components/esp_wifi/include
|
||||
|
||||
#cgo LDFLAGS: -Lesp-idf/components/esp_wifi/lib/esp32c3 -lnet80211 -lpp -lphy -lmesh -lcore
|
||||
#cgo LDFLAGS: -Tesp-idf/components/esp_rom/esp32c3/ld/esp32c3.rom.ld
|
||||
|
||||
#include "esp_private/wifi.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "espnet.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import _ "compat/freertos"
|
||||
|
||||
type ESPWiFi struct {
|
||||
}
|
||||
|
||||
var WiFi = &ESPWiFi{}
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
var internalConfig = C.wifi_init_config_t{
|
||||
osi_funcs: &C.g_wifi_osi_funcs,
|
||||
wpa_crypto_funcs: C.g_wifi_default_wpa_crypto_funcs,
|
||||
static_rx_buf_num: 10,
|
||||
static_tx_buf_num: 10,
|
||||
mgmt_sbuf_num: 6,
|
||||
sta_disconnected_pm: true,
|
||||
magic: C.WIFI_INIT_CONFIG_MAGIC,
|
||||
}
|
||||
|
||||
func (wifi ESPWiFi) Configure(config Config) error {
|
||||
C.esp_wifi_internal_set_log_level(5)
|
||||
return makeError(C.esp_wifi_init_internal(&internalConfig))
|
||||
}
|
||||
|
||||
func (wifi ESPWiFi) AccessPointMAC() ([6]byte, error) {
|
||||
var mac [6]byte
|
||||
errCode := C.esp_wifi_get_mac(C.ESP_IF_WIFI_AP, &mac[0])
|
||||
return mac, makeError(errCode)
|
||||
}
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
package espnet
|
||||
|
||||
// #include <esp_err.h>
|
||||
// #include <esp_wifi.h>
|
||||
import "C"
|
||||
|
||||
// Wrapper for C.esp_err_t. Don't convert a C.esp_err_t to an Error type,
|
||||
// instead use makeError to handle ESP_OK.
|
||||
type Error C.esp_err_t
|
||||
|
||||
// makeError converts a C.esp_err_t into an error or nil depending on whether
|
||||
// errCode indicates an error or not.
|
||||
func makeError(errCode C.esp_err_t) error {
|
||||
if errCode == C.ESP_OK {
|
||||
return nil
|
||||
}
|
||||
return Error(errCode)
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
switch {
|
||||
case e < C.ESP_ERR_WIFI_BASE:
|
||||
// esp-idf/components/esp_common/include/esp_err.h
|
||||
switch e {
|
||||
case C.ESP_OK:
|
||||
return "OK" // not an error
|
||||
case C.ESP_FAIL:
|
||||
return "ESP FAIL"
|
||||
case C.ESP_ERR_NO_MEM:
|
||||
return "Out of memory"
|
||||
case C.ESP_ERR_INVALID_ARG:
|
||||
return "Invalid argument"
|
||||
case C.ESP_ERR_INVALID_STATE:
|
||||
return "Invalid state"
|
||||
case C.ESP_ERR_INVALID_SIZE:
|
||||
return "Invalid size"
|
||||
case C.ESP_ERR_NOT_FOUND:
|
||||
return "Requested resource not found"
|
||||
case C.ESP_ERR_NOT_SUPPORTED:
|
||||
return "Operation or feature not supported"
|
||||
case C.ESP_ERR_TIMEOUT:
|
||||
return "Operation timed out"
|
||||
case C.ESP_ERR_INVALID_RESPONSE:
|
||||
return "Received response was invalid"
|
||||
case C.ESP_ERR_INVALID_CRC:
|
||||
return "CRC or checksum was invalid"
|
||||
case C.ESP_ERR_INVALID_VERSION:
|
||||
return "Version was invalid"
|
||||
case C.ESP_ERR_INVALID_MAC:
|
||||
return "MAC address was invalid"
|
||||
default:
|
||||
return "Unknown error"
|
||||
}
|
||||
case e >= C.ESP_ERR_WIFI_BASE && e < C.ESP_ERR_MESH_BASE:
|
||||
// esp-idf/components/esp_wifi/include/esp_wifi.h
|
||||
switch e {
|
||||
case C.ESP_ERR_WIFI_NOT_INIT:
|
||||
return "WiFi driver was not installed by esp_wifi_init"
|
||||
case C.ESP_ERR_WIFI_NOT_STARTED:
|
||||
return "WiFi driver was not started by esp_wifi_start"
|
||||
case C.ESP_ERR_WIFI_NOT_STOPPED:
|
||||
return "WiFi driver was not stopped by esp_wifi_stop"
|
||||
case C.ESP_ERR_WIFI_IF:
|
||||
return "WiFi interface error"
|
||||
case C.ESP_ERR_WIFI_MODE:
|
||||
return "WiFi mode error"
|
||||
case C.ESP_ERR_WIFI_STATE:
|
||||
return "WiFi internal state error"
|
||||
case C.ESP_ERR_WIFI_CONN:
|
||||
return "WiFi internal control block of station or soft-AP error"
|
||||
case C.ESP_ERR_WIFI_NVS:
|
||||
return "WiFi internal NVS module error"
|
||||
case C.ESP_ERR_WIFI_MAC:
|
||||
return "MAC address is invalid"
|
||||
case C.ESP_ERR_WIFI_SSID:
|
||||
return " SSID is invalid"
|
||||
case C.ESP_ERR_WIFI_PASSWORD:
|
||||
return "Password is invalid"
|
||||
case C.ESP_ERR_WIFI_TIMEOUT:
|
||||
return "Timeout error"
|
||||
case C.ESP_ERR_WIFI_WAKE_FAIL:
|
||||
return "WiFi is in sleep state(RF closed) and wakeup fail"
|
||||
case C.ESP_ERR_WIFI_WOULD_BLOCK:
|
||||
return "The caller would block"
|
||||
case C.ESP_ERR_WIFI_NOT_CONNECT:
|
||||
return "Station still in disconnect status"
|
||||
case C.ESP_ERR_WIFI_POST:
|
||||
return "Failed to post the event to WiFi task"
|
||||
case C.ESP_ERR_WIFI_INIT_STATE:
|
||||
return "Invalid WiFi state when init/deinit is called"
|
||||
case C.ESP_ERR_WIFI_STOP_STATE:
|
||||
return "Returned when WiFi is stopping"
|
||||
case C.ESP_ERR_WIFI_NOT_ASSOC:
|
||||
return "The WiFi connection is not associated"
|
||||
case C.ESP_ERR_WIFI_TX_DISALLOW:
|
||||
return "The WiFi TX is disallowed"
|
||||
default:
|
||||
return "Other WiFi error"
|
||||
}
|
||||
default:
|
||||
return "Other error"
|
||||
}
|
||||
}
|
||||
Submodule espnet/esp-idf deleted from c9646ff0be
-829
@@ -1,829 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "espnet.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_private/wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
|
||||
// Stub functions, to know which functions need to be implemented for OS
|
||||
// functionality.
|
||||
|
||||
static bool _env_is_chip(void) {
|
||||
printf("called: _env_is_chip\n");
|
||||
return false;
|
||||
}
|
||||
static void _set_intr(int32_t cpu_no, uint32_t intr_source, uint32_t intr_num, int32_t intr_prio) {
|
||||
printf("called: _set_intr\n");
|
||||
}
|
||||
static void _clear_intr(uint32_t intr_source, uint32_t intr_num) {
|
||||
printf("called: _clear_intr\n");
|
||||
}
|
||||
static void _set_isr(int32_t n, void *f, void *arg) {
|
||||
printf("called: _set_isr\n");
|
||||
}
|
||||
static void _ints_on(uint32_t mask) {
|
||||
printf("called: _ints_on\n");
|
||||
}
|
||||
static void _ints_off(uint32_t mask) {
|
||||
printf("called: _ints_off\n");
|
||||
}
|
||||
static bool _is_from_isr(void) {
|
||||
printf("called: _is_from_isr\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Having conflict between when include
|
||||
// #include "freertos/portmacro.h"
|
||||
|
||||
typedef struct {
|
||||
/* owner field values:
|
||||
* 0 - Uninitialized (invalid)
|
||||
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
|
||||
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
|
||||
*
|
||||
*
|
||||
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
|
||||
*/
|
||||
uint32_t owner;
|
||||
/* count field:
|
||||
* If mux is unlocked, count should be zero.
|
||||
* If mux is locked, count is non-zero & represents the number of recursive locks on the mux.
|
||||
*/
|
||||
uint32_t count;
|
||||
} portMUX_TYPE;
|
||||
|
||||
#define portMUX_FREE_VAL SPINLOCK_FREE
|
||||
#define SPINLOCK_FREE 0xB33FFFFF
|
||||
|
||||
#define portMUX_INITIALIZER_UNLOCKED { \
|
||||
.owner = portMUX_FREE_VAL, \
|
||||
.count = 0, \
|
||||
}
|
||||
|
||||
static void * _spin_lock_create(void) {
|
||||
portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED;
|
||||
void *mux = malloc(sizeof(portMUX_TYPE));
|
||||
if (mux) {
|
||||
memcpy(mux,&tmp,sizeof(portMUX_TYPE));
|
||||
return mux;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static void _spin_lock_delete(void *lock) {
|
||||
free(lock);
|
||||
}
|
||||
static uint32_t _wifi_int_disable(void *wifi_int_mux) {
|
||||
printf("called: _wifi_int_disable\n");
|
||||
return 0;
|
||||
}
|
||||
static void _wifi_int_restore(void *wifi_int_mux, uint32_t tmp) {
|
||||
printf("called: _wifi_int_restore\n");
|
||||
}
|
||||
static void _task_yield_from_isr(void) {
|
||||
printf("called: _task_yield_from_isr\n");
|
||||
}
|
||||
static void *_semphr_create(uint32_t max, uint32_t init) {
|
||||
return (void *)xSemaphoreCreateCounting(max, init);
|
||||
}
|
||||
static void _semphr_delete(void *semphr) {
|
||||
vSemaphoreDelete(semphr);
|
||||
}
|
||||
static int32_t _semphr_take(void *semphr, uint32_t block_time_tick) {
|
||||
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
|
||||
return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
|
||||
} else {
|
||||
return (int32_t)xSemaphoreTake(semphr, block_time_tick);
|
||||
}
|
||||
}
|
||||
static int32_t _semphr_give(void *semphr) {
|
||||
return (int32_t)xSemaphoreGive(semphr);
|
||||
}
|
||||
static void *_wifi_thread_semphr_get(void) {
|
||||
static SemaphoreHandle_t sem = NULL;
|
||||
if (!sem) {
|
||||
sem = xSemaphoreCreateCounting(1, 0);
|
||||
}
|
||||
return (void*)sem;
|
||||
}
|
||||
static void *_mutex_create(void) {
|
||||
printf("called: _mutex_create\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *_recursive_mutex_create(void) {
|
||||
return xSemaphoreCreateRecursiveMutex();
|
||||
}
|
||||
static void _mutex_delete(void *mutex) {
|
||||
return vSemaphoreDelete(mutex);
|
||||
}
|
||||
static int32_t _mutex_lock(void *mutex) {
|
||||
return (int32_t)xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
||||
}
|
||||
static int32_t _mutex_unlock(void *mutex) {
|
||||
return (int32_t)xSemaphoreGiveRecursive(mutex);
|
||||
}
|
||||
static void * _queue_create(uint32_t queue_len, uint32_t item_size) {
|
||||
printf("called: _queue_create\n");
|
||||
return NULL;
|
||||
}
|
||||
static void _queue_delete(void *queue) {
|
||||
printf("called: _queue_delete\n");
|
||||
}
|
||||
static int32_t _queue_send(void *queue, void *item, uint32_t block_time_tick) {
|
||||
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
|
||||
return (int32_t)xQueueSend(queue, item, portMAX_DELAY);
|
||||
} else {
|
||||
return (int32_t)xQueueSend(queue, item, block_time_tick);
|
||||
}
|
||||
}
|
||||
static int32_t _queue_send_from_isr(void *queue, void *item, void *hptw) {
|
||||
printf("called: _queue_send_from_isr\n");
|
||||
return 0;
|
||||
}
|
||||
static int32_t _queue_send_to_back(void *queue, void *item, uint32_t block_time_tick) {
|
||||
printf("called: _queue_send_to_back\n");
|
||||
return 0;
|
||||
}
|
||||
static int32_t _queue_send_to_front(void *queue, void *item, uint32_t block_time_tick) {
|
||||
printf("called: _queue_send_to_front\n");
|
||||
return 0;
|
||||
}
|
||||
static int32_t _queue_recv(void *queue, void *item, uint32_t block_time_tick) {
|
||||
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
|
||||
return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
|
||||
} else {
|
||||
return (int32_t)xQueueReceive(queue, item, block_time_tick);
|
||||
}
|
||||
}
|
||||
static void * _event_group_create(void) {
|
||||
printf("called: _event_group_create\n");
|
||||
return NULL;
|
||||
}
|
||||
static void _event_group_delete(void *event) {
|
||||
printf("called: _event_group_delete\n");
|
||||
}
|
||||
static uint32_t _event_group_set_bits(void *event, uint32_t bits) {
|
||||
printf("called: _event_group_set_bits\n");
|
||||
return 0;
|
||||
}
|
||||
static uint32_t _event_group_clear_bits(void *event, uint32_t bits) {
|
||||
printf("called: _event_group_clear_bits\n");
|
||||
return 0;
|
||||
}
|
||||
static uint32_t _event_group_wait_bits(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick) {
|
||||
printf("called: _event_group_wait_bits\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define P(x) printf("called: "#x"\n");
|
||||
|
||||
static int32_t _task_create_pinned_to_core(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) {
|
||||
// Note: using xTaskCreate instead of xTaskCreatePinnedToCore.
|
||||
return (uint32_t)xTaskCreate(task_func, name, stack_depth, param, prio, task_handle);
|
||||
}
|
||||
static int32_t _task_create(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle) {
|
||||
P(_task_create)
|
||||
return 0;
|
||||
}
|
||||
static void _task_delete(void *task_handle) {
|
||||
P(_task_delete)
|
||||
}
|
||||
static int32_t _task_ms_to_tick(uint32_t ms) {
|
||||
return (int32_t)(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
static int32_t _task_get_max_priority() {
|
||||
return configMAX_PRIORITIES;
|
||||
}
|
||||
static int32_t _event_post(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait) {
|
||||
P(_event_post)
|
||||
return 0;
|
||||
}
|
||||
static uint32_t _get_free_heap_size(void) {
|
||||
P(_get_free_heap_size)
|
||||
return 0;
|
||||
}
|
||||
static uint32_t _rand(void) {
|
||||
P(_rand)
|
||||
return 0;
|
||||
}
|
||||
static void _dport_access_stall_other_cpu_start_wrap(void) {
|
||||
P(_dport_access_stall_other_cpu_start_wrap)
|
||||
}
|
||||
static void _dport_access_stall_other_cpu_end_wrap(void) {
|
||||
P(_dport_access_stall_other_cpu_end_wrap)
|
||||
}
|
||||
static void _wifi_apb80m_request(void) {
|
||||
P(_wifi_apb80m_request)
|
||||
}
|
||||
static void _wifi_apb80m_release(void) {
|
||||
P(_wifi_apb80m_release)
|
||||
}
|
||||
static void _phy_disable(void) {
|
||||
P(_phy_disable)
|
||||
}
|
||||
static void _phy_enable(void) {
|
||||
P(_phy_enable)
|
||||
}
|
||||
static int _phy_update_country_info(const char* country) {
|
||||
P(_phy_update_country_info)
|
||||
return 0;
|
||||
}
|
||||
static int _read_mac(uint8_t* mac, uint32_t type) {
|
||||
P(_read_mac)
|
||||
return 0;
|
||||
}
|
||||
static void _timer_arm(void *timer, uint32_t tmout, bool repeat) {
|
||||
P(_timer_arm)
|
||||
}
|
||||
static void _timer_disarm(void *timer) {
|
||||
P(_timer_disarm)
|
||||
}
|
||||
static void _timer_done(void *ptimer) {
|
||||
P(_timer_done)
|
||||
}
|
||||
static void _timer_setfn(void *ptimer, void *pfunction, void *parg) {
|
||||
P(_timer_setfn)
|
||||
}
|
||||
static void _timer_arm_us(void *ptimer, uint32_t us, bool repeat) {
|
||||
P(_timer_arm_us)
|
||||
}
|
||||
static void _wifi_reset_mac(void) {
|
||||
P(_wifi_reset_mac)
|
||||
}
|
||||
static void _wifi_clock_enable(void) {
|
||||
P(_wifi_clock_enable)
|
||||
}
|
||||
static void _wifi_clock_disable(void) {
|
||||
P(_wifi_clock_disable)
|
||||
}
|
||||
static void _wifi_rtc_enable_iso(void) {
|
||||
P(_wifi_rtc_enable_iso)
|
||||
}
|
||||
static void _wifi_rtc_disable_iso(void) {
|
||||
P(_wifi_rtc_disable_iso)
|
||||
}
|
||||
static int64_t _esp_timer_get_time(void) {
|
||||
P(_esp_timer_get_time)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_set_i8(uint32_t handle, const char* key, int8_t value) {
|
||||
P(_nvs_set_i8)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_get_i8(uint32_t handle, const char* key, int8_t* out_value) {
|
||||
P(_nvs_get_i8)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_set_u8(uint32_t handle, const char* key, uint8_t value) {
|
||||
P(_nvs_set_u8)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_get_u8(uint32_t handle, const char* key, uint8_t* out_value) {
|
||||
P(_nvs_get_u8)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_set_u16(uint32_t handle, const char* key, uint16_t value) {
|
||||
P(_nvs_set_u16)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_get_u16(uint32_t handle, const char* key, uint16_t* out_value) {
|
||||
P(_nvs_get_u16)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_open(const char* name, uint32_t open_mode, uint32_t *out_handle) {
|
||||
P(_nvs_open)
|
||||
return 0;
|
||||
}
|
||||
static void _nvs_close(uint32_t handle) {
|
||||
P(_nvs_close)
|
||||
}
|
||||
static int _nvs_commit(uint32_t handle) {
|
||||
P(_nvs_commit)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_set_blob(uint32_t handle, const char* key, const void* value, size_t length) {
|
||||
P(_nvs_set_blob)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_get_blob(uint32_t handle, const char* key, void* out_value, size_t* length) {
|
||||
P(_nvs_get_blob)
|
||||
return 0;
|
||||
}
|
||||
static int _nvs_erase_key(uint32_t handle, const char* key) {
|
||||
P(_nvs_erase_key)
|
||||
return 0;
|
||||
}
|
||||
static int _get_random(uint8_t *buf, size_t len) {
|
||||
P(_get_random)
|
||||
return 0;
|
||||
}
|
||||
static int _get_time(void *t) {
|
||||
P(_get_time)
|
||||
return 0;
|
||||
}
|
||||
static unsigned long _random(void) {
|
||||
P(_random)
|
||||
return 0;
|
||||
}
|
||||
// #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
|
||||
// uint32_t (* _slowclk_cal_get(void)
|
||||
// #endif
|
||||
static void _log_write(uint32_t level, const char* tag, const char* format, ...) {
|
||||
va_list argList;
|
||||
printf("[%s] ", tag);
|
||||
va_start(argList, format);
|
||||
vprintf(format, argList);
|
||||
va_end(argList);
|
||||
printf("\n");
|
||||
}
|
||||
static void _log_writev(uint32_t level, const char* tag, const char* format, va_list args) {
|
||||
printf("[%s] ", tag);
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static uint32_t _log_timestamp(void) {
|
||||
P(_log_timestamp)
|
||||
return 0;
|
||||
}
|
||||
static void* _malloc_internal(size_t size) {
|
||||
printf("called: _malloc_internal(%d)\n", size);
|
||||
return malloc(size);
|
||||
}
|
||||
static void* _realloc_internal(void *ptr, size_t size) {
|
||||
printf("called: _realloc_internal(%p,%d)\n", ptr, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* _calloc_internal(size_t n, size_t size) {
|
||||
printf("called: _calloc_internal(%d,%d)\n", n, size);
|
||||
return malloc(n * size);
|
||||
}
|
||||
static void* _zalloc_internal(size_t size) {
|
||||
printf("called: _zalloc_internal(%d)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
static void* _wifi_malloc(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
static void* _wifi_realloc(void *ptr, size_t size) {
|
||||
printf("called: _wifi_realloc(%d)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
static void* _wifi_calloc(size_t n, size_t size) {
|
||||
return calloc(n, size);
|
||||
}
|
||||
static void* _wifi_zalloc(size_t size) {
|
||||
return calloc(1, size);
|
||||
}
|
||||
static void* _wifi_create_queue(int queue_len, int item_size) {
|
||||
wifi_static_queue_t *queue = (wifi_static_queue_t*)malloc(sizeof(wifi_static_queue_t));
|
||||
queue->handle = xQueueCreate( queue_len, item_size);
|
||||
return queue;
|
||||
}
|
||||
static void _wifi_delete_queue(void * queue) {
|
||||
vQueueDelete(queue);
|
||||
}
|
||||
static int _coex_init(void) {
|
||||
P(_coex_init)
|
||||
return 0;
|
||||
}
|
||||
static void _coex_deinit(void) {
|
||||
P(_coex_deinit)
|
||||
}
|
||||
static int _coex_enable(void) {
|
||||
P(_coex_enable)
|
||||
return 0;
|
||||
}
|
||||
static void _coex_disable(void) {
|
||||
P(_coex_disable)
|
||||
}
|
||||
static uint32_t _coex_status_get(void) {
|
||||
P(_coex_status_get)
|
||||
return 0;
|
||||
}
|
||||
static void _coex_condition_set(uint32_t type, bool dissatisfy) {
|
||||
P(_coex_condition_set)
|
||||
}
|
||||
static int _coex_wifi_request(uint32_t event, uint32_t latency, uint32_t duration) {
|
||||
P(_coex_wifi_request)
|
||||
return 0;
|
||||
}
|
||||
static int _coex_wifi_release(uint32_t event) {
|
||||
P(_coex_wifi_release)
|
||||
return 0;
|
||||
}
|
||||
static int _coex_wifi_channel_set(uint8_t primary, uint8_t secondary) {
|
||||
P(_coex_wifi_channel_set)
|
||||
return 0;
|
||||
}
|
||||
static int _coex_event_duration_get(uint32_t event, uint32_t *duration) {
|
||||
P(_coex_event_duration_get)
|
||||
return 0;
|
||||
}
|
||||
static int _coex_pti_get(uint32_t event, uint8_t *pti) {
|
||||
P(_coex_pti_get)
|
||||
return 0;
|
||||
}
|
||||
static void _coex_schm_status_bit_clear(uint32_t type, uint32_t status) {
|
||||
P(_coex_schm_status_bit_clear)
|
||||
}
|
||||
static void _coex_schm_status_bit_set(uint32_t type, uint32_t status) {
|
||||
P(_coex_schm_status_bit_set)
|
||||
}
|
||||
static int _coex_schm_interval_set(uint32_t interval) {
|
||||
P(_coex_schm_interval_set)
|
||||
return 0;
|
||||
}
|
||||
static uint32_t _coex_schm_interval_get(void) {
|
||||
P(_coex_schm_interval_get)
|
||||
return 0;
|
||||
}
|
||||
static uint8_t _coex_schm_curr_period_get(void) {
|
||||
P(_coex_schm_curr_period_get)
|
||||
return 0;
|
||||
}
|
||||
static void* _coex_schm_curr_phase_get(void) {
|
||||
P(_coex_schm_curr_phase_get)
|
||||
return NULL;
|
||||
}
|
||||
static int _coex_schm_curr_phase_idx_set(int idx) {
|
||||
P(_coex_schm_curr_phase_idx_set)
|
||||
return 0;
|
||||
}
|
||||
static int _coex_schm_curr_phase_idx_get(void) {
|
||||
P(_coex_schm_curr_phase_idx_get)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t _slowclk_cal_get(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OS adapter functions.
|
||||
// See: esp-idf/components/esp_wifi/include/esp_private/wifi_os_adapter.h
|
||||
wifi_osi_funcs_t g_wifi_osi_funcs = {
|
||||
._version = ESP_WIFI_OS_ADAPTER_VERSION,
|
||||
._env_is_chip = _env_is_chip,
|
||||
._set_intr = _set_intr,
|
||||
._clear_intr = _clear_intr,
|
||||
._set_isr = _set_isr,
|
||||
._ints_on = _ints_on,
|
||||
._ints_off = _ints_off,
|
||||
._is_from_isr = _is_from_isr,
|
||||
._spin_lock_create = _spin_lock_create,
|
||||
._spin_lock_delete = _spin_lock_delete,
|
||||
._wifi_int_disable = _wifi_int_disable,
|
||||
._wifi_int_restore = _wifi_int_restore,
|
||||
._task_yield_from_isr = _task_yield_from_isr,
|
||||
._semphr_create = _semphr_create,
|
||||
._semphr_delete = _semphr_delete,
|
||||
._semphr_take = _semphr_take,
|
||||
._semphr_give = _semphr_give,
|
||||
._wifi_thread_semphr_get = _wifi_thread_semphr_get,
|
||||
._mutex_create = _mutex_create,
|
||||
._recursive_mutex_create = _recursive_mutex_create,
|
||||
._mutex_delete = _mutex_delete,
|
||||
._mutex_lock = _mutex_lock,
|
||||
._mutex_unlock = _mutex_unlock,
|
||||
._queue_create = _queue_create,
|
||||
._queue_delete = _queue_delete,
|
||||
._queue_send = _queue_send,
|
||||
._queue_send_from_isr = _queue_send_from_isr,
|
||||
._queue_send_to_back = _queue_send_to_back,
|
||||
._queue_send_to_front = _queue_send_to_front,
|
||||
._queue_recv = _queue_recv,
|
||||
._queue_msg_waiting = (uint32_t(*)(void *))uxQueueMessagesWaiting,
|
||||
._event_group_create = _event_group_create,
|
||||
._event_group_delete = _event_group_delete,
|
||||
._event_group_set_bits = _event_group_set_bits,
|
||||
._event_group_clear_bits = _event_group_clear_bits,
|
||||
._event_group_wait_bits = _event_group_wait_bits,
|
||||
._task_create_pinned_to_core = _task_create_pinned_to_core,
|
||||
._task_create = _task_create,
|
||||
._task_delete = _task_delete,
|
||||
._task_delay = vTaskDelay,
|
||||
._task_ms_to_tick = _task_ms_to_tick,
|
||||
._task_get_current_task = (void *(*)(void))xTaskGetCurrentTaskHandle,
|
||||
._task_get_max_priority = _task_get_max_priority,
|
||||
._malloc = malloc,
|
||||
._free = free,
|
||||
._event_post = _event_post,
|
||||
._get_free_heap_size = _get_free_heap_size,
|
||||
._rand = _rand,
|
||||
._dport_access_stall_other_cpu_start_wrap = _dport_access_stall_other_cpu_start_wrap,
|
||||
._dport_access_stall_other_cpu_end_wrap = _dport_access_stall_other_cpu_end_wrap,
|
||||
._wifi_apb80m_request = _wifi_apb80m_request,
|
||||
._wifi_apb80m_release = _wifi_apb80m_release,
|
||||
._phy_disable = _phy_disable,
|
||||
._phy_enable = _phy_enable,
|
||||
._phy_update_country_info = _phy_update_country_info,
|
||||
._read_mac = _read_mac,
|
||||
._timer_arm = _timer_arm,
|
||||
._timer_disarm = _timer_disarm,
|
||||
._timer_done = _timer_done,
|
||||
._timer_setfn = _timer_setfn,
|
||||
._timer_arm_us = _timer_arm_us,
|
||||
._wifi_reset_mac = _wifi_reset_mac,
|
||||
._wifi_clock_enable = _wifi_clock_enable,
|
||||
._wifi_clock_disable = _wifi_clock_disable,
|
||||
._wifi_rtc_enable_iso = _wifi_rtc_enable_iso,
|
||||
._wifi_rtc_disable_iso = _wifi_rtc_disable_iso,
|
||||
._esp_timer_get_time = _esp_timer_get_time,
|
||||
._nvs_set_i8 = _nvs_set_i8,
|
||||
._nvs_get_i8 = _nvs_get_i8,
|
||||
._nvs_set_u8 = _nvs_set_u8,
|
||||
._nvs_get_u8 = _nvs_get_u8,
|
||||
._nvs_set_u16 = _nvs_set_u16,
|
||||
._nvs_get_u16 = _nvs_get_u16,
|
||||
._nvs_open = _nvs_open,
|
||||
._nvs_close = _nvs_close,
|
||||
._nvs_commit = _nvs_commit,
|
||||
._nvs_set_blob = _nvs_set_blob,
|
||||
._nvs_get_blob = _nvs_get_blob,
|
||||
._nvs_erase_key = _nvs_erase_key,
|
||||
._get_random = _get_random,
|
||||
._get_time = _get_time,
|
||||
._random = _random,
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
|
||||
._slowclk_cal_get = _slowclk_cal_get,
|
||||
#endif
|
||||
._log_write = _log_write,
|
||||
._log_writev = _log_writev,
|
||||
._log_timestamp = _log_timestamp,
|
||||
._malloc_internal = _malloc_internal,
|
||||
._realloc_internal = _realloc_internal,
|
||||
._calloc_internal = _calloc_internal,
|
||||
._zalloc_internal = _zalloc_internal,
|
||||
._wifi_malloc = _wifi_malloc,
|
||||
._wifi_realloc = _wifi_realloc,
|
||||
._wifi_calloc = _wifi_calloc,
|
||||
._wifi_zalloc = _wifi_zalloc,
|
||||
._wifi_create_queue = _wifi_create_queue,
|
||||
._wifi_delete_queue = _wifi_delete_queue,
|
||||
._coex_init = _coex_init,
|
||||
._coex_deinit = _coex_deinit,
|
||||
._coex_enable = _coex_enable,
|
||||
._coex_disable = _coex_disable,
|
||||
._coex_status_get = _coex_status_get,
|
||||
._coex_condition_set = _coex_condition_set,
|
||||
._coex_wifi_request = _coex_wifi_request,
|
||||
._coex_wifi_release = _coex_wifi_release,
|
||||
._coex_wifi_channel_set = _coex_wifi_channel_set,
|
||||
._coex_event_duration_get = _coex_event_duration_get,
|
||||
._coex_pti_get = _coex_pti_get,
|
||||
._coex_schm_status_bit_clear = _coex_schm_status_bit_clear,
|
||||
._coex_schm_status_bit_set = _coex_schm_status_bit_set,
|
||||
._coex_schm_interval_set = _coex_schm_interval_set,
|
||||
._coex_schm_interval_get = _coex_schm_interval_get,
|
||||
._coex_schm_curr_period_get = _coex_schm_curr_period_get,
|
||||
._coex_schm_curr_phase_get = _coex_schm_curr_phase_get,
|
||||
._coex_schm_curr_phase_idx_set = _coex_schm_curr_phase_idx_set,
|
||||
._coex_schm_curr_phase_idx_get = _coex_schm_curr_phase_idx_get,
|
||||
|
||||
._magic = ESP_WIFI_OS_ADAPTER_MAGIC,
|
||||
};
|
||||
|
||||
static int esp_aes_wrap(const unsigned char *kek, int n, const unsigned char *plain, unsigned char *cipher) {
|
||||
P(aes_wrap)
|
||||
return -1;
|
||||
}
|
||||
static int esp_aes_unwrap(const unsigned char *kek, int n, const unsigned char *cipher, unsigned char *plain) {
|
||||
P(aes_unwrap)
|
||||
return -1;
|
||||
}
|
||||
static int hmac_sha256_vector(const unsigned char *key, int key_len, int num_elem,
|
||||
const unsigned char *addr[], const int *len, unsigned char *mac) {
|
||||
return -1;
|
||||
}
|
||||
static int sha256_prf(const unsigned char *key, int key_len, const char *label,
|
||||
const unsigned char *data, int data_len, unsigned char *buf, int buf_len) {
|
||||
P(sha256_prf)
|
||||
return -1;
|
||||
}
|
||||
static int hmac_md5(const unsigned char *key, unsigned int key_len, const unsigned char *data,
|
||||
unsigned int data_len, unsigned char *mac) {
|
||||
P(hmac_md5)
|
||||
return -1;
|
||||
}
|
||||
static int hamc_md5_vector(const unsigned char *key, unsigned int key_len, unsigned int num_elem,
|
||||
const unsigned char *addr[], const unsigned int *len, unsigned char *mac) {
|
||||
P(hamc_md5_vector)
|
||||
return -1;
|
||||
}
|
||||
static int hmac_sha1(const unsigned char *key, unsigned int key_len, const unsigned char *data,
|
||||
unsigned int data_len, unsigned char *mac) {
|
||||
P(hmac_sha1)
|
||||
return -1;
|
||||
}
|
||||
static int hmac_sha1_vector(const unsigned char *key, unsigned int key_len, unsigned int num_elem,
|
||||
const unsigned char *addr[], const unsigned int *len, unsigned char *mac) {
|
||||
P(hmac_sha1_vector)
|
||||
return -1;
|
||||
}
|
||||
static int sha1_prf(const unsigned char *key, unsigned int key_len, const char *label,
|
||||
const unsigned char *data, unsigned int data_len, unsigned char *buf, unsigned int buf_len) {
|
||||
P(sha1_prf)
|
||||
return -1;
|
||||
}
|
||||
static int sha1_vector(unsigned int num_elem, const unsigned char *addr[], const unsigned int *len,
|
||||
unsigned char *mac) {
|
||||
P(sha1_vector)
|
||||
return -1;
|
||||
}
|
||||
static int pbkdf2_sha1(const char *passphrase, const char *ssid, unsigned int ssid_len,
|
||||
int iterations, unsigned char *buf, unsigned int buflen) {
|
||||
P(pbkdf2_sha1)
|
||||
return -1;
|
||||
}
|
||||
static int rc4_skip(const unsigned char *key, unsigned int keylen, unsigned int skip,
|
||||
unsigned char *data, unsigned int data_len) {
|
||||
P(rc4_skip)
|
||||
return -1;
|
||||
}
|
||||
static int md5_vector(unsigned int num_elem, const unsigned char *addr[], const unsigned int *len,
|
||||
unsigned char *mac) {
|
||||
P(md5_vector)
|
||||
return -1;
|
||||
}
|
||||
static void aes_encrypt(void *ctx, const unsigned char *plain, unsigned char *crypt) {
|
||||
P(aes_encrypt)
|
||||
}
|
||||
static void * aes_encrypt_init(const unsigned char *key, unsigned int len) {
|
||||
P(aes_encrypt_init)
|
||||
return NULL;
|
||||
}
|
||||
static void aes_encrypt_deinit(void *ctx) {
|
||||
P(aes_encrypt_deinit)
|
||||
}
|
||||
static void aes_decrypt(void *ctx, const unsigned char *crypt, unsigned char *plain) {
|
||||
P(aes_decrypt)
|
||||
}
|
||||
static void * aes_decrypt_init(const unsigned char *key, unsigned int len) {
|
||||
P(aes_decrypt_init)
|
||||
return NULL;
|
||||
}
|
||||
static void aes_decrypt_deinit(void *ctx) {
|
||||
P(aes_decrypt_deinit)
|
||||
}
|
||||
static int aes_128_decrypt(const unsigned char *key, const unsigned char *iv, unsigned char *data, int data_len) {
|
||||
P(aes_128_decrypt)
|
||||
return -1;
|
||||
}
|
||||
static int omac1_aes_128(const uint8_t *key, const uint8_t *data, size_t data_len,
|
||||
uint8_t *mic) {
|
||||
P(omac1_aes_128)
|
||||
return -1;
|
||||
}
|
||||
static uint8_t * ccmp_decrypt(const uint8_t *tk, const uint8_t *ieee80211_hdr,
|
||||
const uint8_t *data, size_t data_len,
|
||||
size_t *decrypted_len, bool espnow_pkt) {
|
||||
P(ccmp_decrypt)
|
||||
return NULL;
|
||||
}
|
||||
static uint8_t * ccmp_encrypt(const uint8_t *tk, uint8_t *frame, size_t len, size_t hdrlen,
|
||||
uint8_t *pn, int keyid, size_t *encrypted_len) {
|
||||
P(ccmp_encrypt)
|
||||
return NULL;
|
||||
}
|
||||
static int hmac_md5_vector(const unsigned char *key, unsigned int key_len, unsigned int num_elem,
|
||||
const unsigned char *addr[], const unsigned int *len, unsigned char *mac) {
|
||||
P(hmac_md5_vector)
|
||||
return -1;
|
||||
}
|
||||
static void esp_aes_encrypt(void *ctx, const unsigned char *plain, unsigned char *crypt) {
|
||||
P(esp_aes_encrypt)
|
||||
}
|
||||
static void esp_aes_decrypt(void *ctx, const unsigned char *crypt, unsigned char *plain) {
|
||||
P(esp_aes_decrypt)
|
||||
}
|
||||
static int aes_128_cbc_encrypt(const unsigned char *key, const unsigned char *iv, unsigned char *data, int data_len) {
|
||||
P(aes_128_cbc_encrypt)
|
||||
return -1;
|
||||
}
|
||||
static int aes_128_cbc_decrypt(const unsigned char *key, const unsigned char *iv, unsigned char *data, int data_len) {
|
||||
P(aes_128_cbc_decrypt)
|
||||
return -1;
|
||||
}
|
||||
|
||||
const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = {
|
||||
.size = sizeof(wpa_crypto_funcs_t),
|
||||
.version = ESP_WIFI_CRYPTO_VERSION,
|
||||
.aes_wrap = (esp_aes_wrap_t)esp_aes_wrap,
|
||||
.aes_unwrap = (esp_aes_unwrap_t)esp_aes_unwrap,
|
||||
.hmac_sha256_vector = (esp_hmac_sha256_vector_t)hmac_sha256_vector,
|
||||
.sha256_prf = (esp_sha256_prf_t)sha256_prf,
|
||||
.hmac_md5 = (esp_hmac_md5_t)hmac_md5,
|
||||
.hamc_md5_vector = (esp_hmac_md5_vector_t)hmac_md5_vector,
|
||||
.hmac_sha1 = (esp_hmac_sha1_t)hmac_sha1,
|
||||
.hmac_sha1_vector = (esp_hmac_sha1_vector_t)hmac_sha1_vector,
|
||||
.sha1_prf = (esp_sha1_prf_t)sha1_prf,
|
||||
.sha1_vector = (esp_sha1_vector_t)sha1_vector,
|
||||
.pbkdf2_sha1 = (esp_pbkdf2_sha1_t)pbkdf2_sha1,
|
||||
.rc4_skip = (esp_rc4_skip_t)rc4_skip,
|
||||
.md5_vector = (esp_md5_vector_t)md5_vector,
|
||||
.aes_encrypt = (esp_aes_encrypt_t)esp_aes_encrypt,
|
||||
.aes_encrypt_init = (esp_aes_encrypt_init_t)aes_encrypt_init,
|
||||
.aes_encrypt_deinit = (esp_aes_encrypt_deinit_t)aes_encrypt_deinit,
|
||||
.aes_decrypt = (esp_aes_decrypt_t)esp_aes_decrypt,
|
||||
.aes_decrypt_init = (esp_aes_decrypt_init_t)aes_decrypt_init,
|
||||
.aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit,
|
||||
.aes_128_encrypt = (esp_aes_128_encrypt_t)aes_128_cbc_encrypt,
|
||||
.aes_128_decrypt = (esp_aes_128_decrypt_t)aes_128_cbc_decrypt,
|
||||
.omac1_aes_128 = (esp_omac1_aes_128_t)omac1_aes_128,
|
||||
.ccmp_decrypt = (esp_ccmp_decrypt_t)ccmp_decrypt,
|
||||
.ccmp_encrypt = (esp_ccmp_encrypt_t)ccmp_encrypt
|
||||
};
|
||||
|
||||
// This is a string constant that is used all over ESP-IDF and is also used by
|
||||
// libnet80211.a. The main purpose is to be a fixed pointer that can be compared
|
||||
// against etc.
|
||||
const char *WIFI_EVENT = "WIFI_EVENT";
|
||||
|
||||
// Required by libphy.a
|
||||
int phy_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
printf("phy: ");
|
||||
int res = vprintf(format, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Required by libpp.a
|
||||
int pp_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
printf("pp: ");
|
||||
int res = vprintf(format, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Required by libnet80211.a
|
||||
int net80211_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
printf("net80211: ");
|
||||
int res = vprintf(format, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Source: esp-idf/components/wpa_supplicant/src/utils/common.c
|
||||
static int hex2num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Source: esp-idf/components/wpa_supplicant/src/utils/common.c
|
||||
int hex2byte(const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = hex2num(*hex++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = hex2num(*hex++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
// Source: esp-idf/components/wpa_supplicant/src/utils/common.c
|
||||
/**
|
||||
* hexstr2bin - Convert ASCII hex string into binary data
|
||||
* @hex: ASCII hex string (e.g., "01ab")
|
||||
* @buf: Buffer for the binary data
|
||||
* @len: Length of the text to convert in bytes (of buf); hex will be double
|
||||
* this size
|
||||
* Returns: 0 on success, -1 on failure (invalid hex string)
|
||||
*/
|
||||
int hexstr2bin(const char *hex, uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
int a;
|
||||
const char *ipos = hex;
|
||||
uint8_t *opos = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
a = hex2byte(ipos);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
*opos++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_private/wifi_os_adapter.h"
|
||||
|
||||
extern wifi_osi_funcs_t g_wifi_osi_funcs;
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableColor() // enable color engine
|
||||
|
||||
for {
|
||||
|
||||
if sensor.ColorAvailable() {
|
||||
r, g, b, c := sensor.ReadColor()
|
||||
println("Red =", r, "\tGreen =", g, "\tBlue =", b, "\tClear =", c)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableGesture() // enable gesture engine
|
||||
|
||||
for {
|
||||
|
||||
// wave your hand (not too slow) about 10 cm above the sensor
|
||||
if sensor.GestureAvailable() {
|
||||
|
||||
gesture := sensor.ReadGesture()
|
||||
print("Detected gesture: ")
|
||||
switch gesture {
|
||||
case apds9960.GESTURE_UP:
|
||||
println("Up")
|
||||
case apds9960.GESTURE_DOWN:
|
||||
println("Down")
|
||||
case apds9960.GESTURE_LEFT:
|
||||
println("Left")
|
||||
case apds9960.GESTURE_RIGHT:
|
||||
println("Right")
|
||||
}
|
||||
}
|
||||
// note: the delay shouldn't be too long, otherwise new gesture data might be lost
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/apds9960"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableProximity() // enable proximity engine
|
||||
|
||||
for {
|
||||
|
||||
if sensor.ProximityAvailable() {
|
||||
p := sensor.ReadProximity()
|
||||
println("Proximity:", p)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
|
||||
for {
|
||||
led.Low()
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
led.High()
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import "tinygo.org/x/drivers/espnet"
|
||||
|
||||
func main() {
|
||||
err := espnet.WiFi.Configure(espnet.Config{})
|
||||
if err != nil {
|
||||
println("failed to configure:", err.Error())
|
||||
}
|
||||
mac, err := espnet.WiFi.AccessPointMAC()
|
||||
if err != nil {
|
||||
println("failed to read MAC address:", err.Error())
|
||||
return
|
||||
}
|
||||
print("MAC address:")
|
||||
for _, b := range mac {
|
||||
print(" ", b)
|
||||
}
|
||||
println()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/hts221"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := hts221.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("HTS221 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure() // power on and calibrate
|
||||
|
||||
for {
|
||||
|
||||
h, _ := sensor.ReadHumidity()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("h =", float32(h)/100.0, "% / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/adt7410"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := i2csoft.New(machine.SCL_PIN, machine.SDA_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{
|
||||
Frequency: 400e3,
|
||||
})
|
||||
|
||||
sensor := adt7410.New(i2c)
|
||||
sensor.Configure()
|
||||
|
||||
for {
|
||||
temp := sensor.ReadTempF()
|
||||
fmt.Printf("temperature: %f\r\n", temp)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D0,
|
||||
machine.D1,
|
||||
machine.D2,
|
||||
)
|
||||
|
||||
backlight = machine.D3
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 24000000,
|
||||
})
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
@@ -16,16 +16,15 @@ var (
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display.Configure(ili9341.Config{})
|
||||
width, height := display.Size()
|
||||
|
||||
display.FillScreen(black)
|
||||
backlight.High()
|
||||
|
||||
display.FillRectangle(0, 0, width/2, height/2, white)
|
||||
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
||||
display.FillRectangle(0, height/2, width/2, height/2, green)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
backlight = machine.TFT_BACKLIGHT
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
backlight = machine.LCD_BACKLIGHT
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI3.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 24000000,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.D3
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D0,
|
||||
machine.D1,
|
||||
machine.D2,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
display := ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.TFT_BACKLIGHT
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
+22
-13
@@ -1,7 +1,7 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
@@ -9,22 +9,31 @@ import (
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
backlight = machine.LCD_BACKLIGHT
|
||||
)
|
||||
|
||||
func init() {
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI3.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.LCD_BACKLIGHT
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
@@ -44,20 +44,17 @@ var (
|
||||
palette [16]uint16
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
// configure backlight
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{})
|
||||
print("width, height == ")
|
||||
width, height := display.Size()
|
||||
println(width, height)
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation270)
|
||||
DrawBackground()
|
||||
|
||||
startTime = time.Now().UnixNano()
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
backlight = machine.TFT_BACKLIGHT
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D0,
|
||||
machine.D1,
|
||||
machine.D2,
|
||||
)
|
||||
|
||||
backlight = machine.D3
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 24000000,
|
||||
})
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
@@ -16,16 +16,15 @@ var (
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
display := initdisplay.InitDisplay()
|
||||
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display.Configure(ili9341.Config{})
|
||||
width, height := display.Size()
|
||||
|
||||
display.FillScreen(black)
|
||||
backlight.High()
|
||||
|
||||
display.FillRectangle(0, 0, width/2, height/2, white)
|
||||
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
||||
display.FillRectangle(0, height/2, width/2, height/2, green)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
backlight = machine.TFT_BACKLIGHT
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
backlight = machine.LCD_BACKLIGHT
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI3.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI0,
|
||||
machine.D0,
|
||||
machine.D1,
|
||||
machine.D2,
|
||||
)
|
||||
|
||||
backlight = machine.D3
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 24000000,
|
||||
})
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"machine"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
"tinygo.org/x/drivers/image/jpeg"
|
||||
"tinygo.org/x/drivers/image/png"
|
||||
@@ -20,6 +20,10 @@ var (
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
)
|
||||
|
||||
var (
|
||||
display *ili9341.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := run()
|
||||
for err != nil {
|
||||
@@ -28,9 +32,7 @@ func main() {
|
||||
}
|
||||
|
||||
func run() error {
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display.Configure(ili9341.Config{})
|
||||
display = initdisplay.InitDisplay()
|
||||
|
||||
width, height := display.Size()
|
||||
if width < 320 || height < 240 {
|
||||
@@ -38,7 +40,6 @@ func run() error {
|
||||
}
|
||||
|
||||
display.FillScreen(black)
|
||||
backlight.High()
|
||||
|
||||
for {
|
||||
err := drawJpeg(display)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewParallel(
|
||||
machine.LCD_DATA0,
|
||||
machine.TFT_WR,
|
||||
machine.TFT_DC,
|
||||
machine.TFT_CS,
|
||||
machine.TFT_RESET,
|
||||
machine.TFT_RD,
|
||||
)
|
||||
|
||||
backlight = machine.TFT_BACKLIGHT
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
var (
|
||||
display = ili9341.NewSPI(
|
||||
machine.SPI3,
|
||||
machine.LCD_DC,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RESET,
|
||||
)
|
||||
|
||||
backlight = machine.LCD_BACKLIGHT
|
||||
)
|
||||
|
||||
func init() {
|
||||
machine.SPI3.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40000000,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lps22hb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := lps22hb.New(machine.I2C1)
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("LPS22HB not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure()
|
||||
|
||||
for {
|
||||
|
||||
p, _ := sensor.ReadPressure()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("p =", float32(p)/1000.0, "hPa / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
// note: the device would power down itself after each query
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// LSM9DS1, 9 axis Inertial Measurement Unit (IMU)
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm9ds1"
|
||||
)
|
||||
|
||||
const (
|
||||
PLOTTER = false
|
||||
SHOW_ACCELERATION = true
|
||||
SHOW_ROTATION = true
|
||||
SHOW_MAGNETIC_FIELD = true
|
||||
SHOW_TEMPERATURE = true
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// I2C configure
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
// LSM9DS1 setup
|
||||
device := lsm9ds1.New(machine.I2C0)
|
||||
err := device.Configure(lsm9ds1.Configuration{
|
||||
AccelRange: lsm9ds1.ACCEL_2G,
|
||||
AccelSampleRate: lsm9ds1.ACCEL_SR_119,
|
||||
GyroRange: lsm9ds1.GYRO_250DPS,
|
||||
GyroSampleRate: lsm9ds1.GYRO_SR_119,
|
||||
MagRange: lsm9ds1.MAG_4G,
|
||||
MagSampleRate: lsm9ds1.MAG_SR_40,
|
||||
})
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
if con, err := device.Connected(); !con || err != nil {
|
||||
println("LSM9DS1 not connected")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
ax, ay, az, _ := device.ReadAcceleration()
|
||||
gx, gy, gz, _ := device.ReadRotation()
|
||||
mx, my, mz, _ := device.ReadMagneticField()
|
||||
t, _ := device.ReadTemperature()
|
||||
|
||||
if PLOTTER {
|
||||
printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
} else {
|
||||
printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t)
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Arduino IDE's Serial Plotter
|
||||
func printPlotter(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("AX:%f, AY:%f, AZ:%f,", axis(ax), axis(ay), axis(az))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("GX:%f, GY:%f, GZ:%f,", axis(gx), axis(gy), axis(gz))
|
||||
}
|
||||
if SHOW_MAGNETIC_FIELD {
|
||||
fmt.Printf("MX:%d, MY:%d, MZ:%d,", mx, my, mz)
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("T:%f", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
// Any Serial Monitor
|
||||
func printMonitor(ax, ay, az, gx, gy, gz, mx, my, mz, t int32) {
|
||||
if SHOW_ACCELERATION {
|
||||
fmt.Printf("Acceleration (g): %f, %f, %f\r\n", axis(ax), axis(ay), axis(az))
|
||||
}
|
||||
if SHOW_ROTATION {
|
||||
fmt.Printf("Rotation (dps): %f, %f, %f\r\n", axis(gx), axis(gy), axis(gz))
|
||||
}
|
||||
if SHOW_MAGNETIC_FIELD {
|
||||
fmt.Printf("Magnetic field (nT): %d, %d, %d\r\n", mx, my, mz)
|
||||
}
|
||||
if SHOW_TEMPERATURE {
|
||||
fmt.Printf("Temperature C: %f\r\n", float32(t)/1000)
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
func axis(raw int32) float32 {
|
||||
return float32(raw) / 1000000
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
//go:build nano_rp2040
|
||||
// +build nano_rp2040
|
||||
|
||||
// This examples shows how to control RGB LED connected to
|
||||
// NINA-W102 chip on Arduino Nano RP2040 Connect board
|
||||
// Built-in LED code added for API comparison
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/wifinina"
|
||||
)
|
||||
|
||||
const (
|
||||
LED = machine.LED
|
||||
|
||||
// Arduino Nano RP2040 Connect board RGB LED pins
|
||||
// See https://docs.arduino.cc/static/3525d638b5c76a2d19588d6b41cd02a0/ABX00053-full-pinout.pdf
|
||||
LED_R wifinina.Pin = 27
|
||||
LED_G wifinina.Pin = 25
|
||||
LED_B wifinina.Pin = 26
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// these are the default pins for the Arduino Nano-RP2040 Connect
|
||||
spi = machine.NINA_SPI
|
||||
|
||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
||||
device *wifinina.Device
|
||||
)
|
||||
|
||||
func setup() {
|
||||
|
||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||
spi.Configure(machine.SPIConfig{
|
||||
Frequency: 8 * 1e6,
|
||||
SDO: machine.NINA_SDO,
|
||||
SDI: machine.NINA_SDI,
|
||||
SCK: machine.NINA_SCK,
|
||||
})
|
||||
|
||||
device = wifinina.New(spi,
|
||||
machine.NINA_CS,
|
||||
machine.NINA_ACK,
|
||||
machine.NINA_GPIO0,
|
||||
machine.NINA_RESETN)
|
||||
device.Configure()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
LED_R.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
||||
LED_G.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
||||
LED_B.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
setup()
|
||||
|
||||
LED.Low() // OFF
|
||||
LED_R.High() // OFF
|
||||
LED_G.High() // OFF
|
||||
LED_B.High() // OFF
|
||||
|
||||
go func() {
|
||||
for {
|
||||
LED.Low()
|
||||
time.Sleep(time.Second)
|
||||
LED.High()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
LED_R.Low() // ON
|
||||
time.Sleep(time.Second)
|
||||
LED_R.High() // OFF
|
||||
LED_G.Low() // ON
|
||||
time.Sleep(time.Second)
|
||||
LED_G.High() // OFF
|
||||
LED_B.Low() // ON
|
||||
time.Sleep(time.Second)
|
||||
LED_B.High() // OFF
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// Package hts221 implements a driver for HTS221,
|
||||
// a capacitive digital sensor for relative humidity and temperature.
|
||||
//
|
||||
// Datasheet: https://www.st.com/resource/en/datasheet/hts221.pdf
|
||||
//
|
||||
package hts221
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a HTS221 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
humiditySlope float32
|
||||
humidityZero float32
|
||||
temperatureSlope float32
|
||||
temperatureZero float32
|
||||
}
|
||||
|
||||
// Connected returns whether HTS221 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, HTS221_WHO_AM_I_REG, data)
|
||||
return data[0] == 0xBC
|
||||
}
|
||||
|
||||
// Configure sets up the HTS221 device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// read calibration data
|
||||
d.calibration()
|
||||
// activate device and use block data update mode
|
||||
d.Power(true)
|
||||
}
|
||||
|
||||
// Power is for turn on/off the HTS221 device
|
||||
func (d *Device) Power(status bool) {
|
||||
data := []byte{0}
|
||||
if status {
|
||||
data[0] = 0x84
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, HTS221_CTRL1_REG, data)
|
||||
}
|
||||
|
||||
// ReadHumidity returns the relative humidity in percent * 100.
|
||||
// Returns an error if the device is not turned on.
|
||||
func (d *Device) ReadHumidity() (humidity int32, err error) {
|
||||
err = d.waitForOneShot(0x02)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// read data and calibrate
|
||||
data := []byte{0, 0}
|
||||
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_HUMID_OUT_REG+1, data[1:])
|
||||
hValue := readInt(data[1], data[0])
|
||||
hValueCalib := float32(hValue)*d.humiditySlope + d.humidityZero
|
||||
|
||||
return int32(hValueCalib * 100), nil
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
// Returns an error if the device is not turned on.
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
err = d.waitForOneShot(0x01)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// read data and calibrate
|
||||
data := []byte{0, 0}
|
||||
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_TEMP_OUT_REG+1, data[1:])
|
||||
tValue := readInt(data[1], data[0])
|
||||
tValueCalib := float32(tValue)*d.temperatureSlope + d.temperatureZero
|
||||
|
||||
return int32(tValueCalib * 1000), nil
|
||||
}
|
||||
|
||||
// Resolution sets the HTS221's resolution mode.
|
||||
// The higher resolutions are more accurate but comsume more power (see datasheet).
|
||||
// The number of averaged samples will be (h + 2) ^ 2, (t + 1) ^ 2
|
||||
//
|
||||
func (d *Device) Resolution(h uint8, t uint8) {
|
||||
if h > 7 {
|
||||
h = 3 // default
|
||||
}
|
||||
if t > 7 {
|
||||
t = 3 // default
|
||||
}
|
||||
d.bus.WriteRegister(d.Address, HTS221_AV_CONF_REG, []byte{h<<3 | t})
|
||||
}
|
||||
|
||||
// private functions
|
||||
|
||||
// read factory calibration data
|
||||
func (d *Device) calibration() {
|
||||
h0rH, h1rH := []byte{0}, []byte{0}
|
||||
t0degC, t1degC := []byte{0}, []byte{0}
|
||||
t1t0msb := []byte{0}
|
||||
h0t0Out, h1t0Out := []byte{0, 0}, []byte{0, 0}
|
||||
t0Out, t1Out := []byte{0, 0}, []byte{0, 0}
|
||||
|
||||
d.bus.ReadRegister(d.Address, HTS221_H0_rH_x2_REG, h0rH)
|
||||
d.bus.ReadRegister(d.Address, HTS221_H1_rH_x2_REG, h1rH)
|
||||
d.bus.ReadRegister(d.Address, HTS221_T0_degC_x8_REG, t0degC)
|
||||
d.bus.ReadRegister(d.Address, HTS221_T1_degC_x8_REG, t1degC)
|
||||
d.bus.ReadRegister(d.Address, HTS221_T1_T0_MSB_REG, t1t0msb)
|
||||
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG, h0t0Out[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_H0_T0_OUT_REG+1, h0t0Out[1:])
|
||||
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG, h1t0Out[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_H1_T0_OUT_REG+1, h1t0Out[1:])
|
||||
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG, t0Out[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_T0_OUT_REG+1, t0Out[1:])
|
||||
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG, t1Out[:1])
|
||||
d.bus.ReadRegister(d.Address, HTS221_T1_OUT_REG+1, t1Out[1:])
|
||||
|
||||
h0rH_v := float32(h0rH[0]) / 2.0
|
||||
h1rH_v := float32(h1rH[0]) / 2.0
|
||||
t0degC_v := float32(readUint(t1t0msb[0]&0x03, t0degC[0])) / 8.0
|
||||
t1degC_v := float32(readUint(t1t0msb[0]&0x0C>>2, t1degC[0])) / 8.0
|
||||
h0t0Out_v := float32(readInt(h0t0Out[1], h0t0Out[0]))
|
||||
h1t0Out_v := float32(readInt(h1t0Out[1], h1t0Out[0]))
|
||||
t0Out_v := float32(readInt(t0Out[1], t0Out[0]))
|
||||
t1Out_v := float32(readInt(t1Out[1], t1Out[0]))
|
||||
|
||||
d.humiditySlope = (h1rH_v - h0rH_v) / (h1t0Out_v - h0t0Out_v)
|
||||
d.humidityZero = h0rH_v - d.humiditySlope*h0t0Out_v
|
||||
d.temperatureSlope = (t1degC_v - t0degC_v) / (t1Out_v - t0Out_v)
|
||||
d.temperatureZero = t0degC_v - d.temperatureSlope*t0Out_v
|
||||
}
|
||||
|
||||
// wait and trigger one shot in block update
|
||||
func (d *Device) waitForOneShot(filter uint8) error {
|
||||
data := []byte{0}
|
||||
|
||||
// check if the device is on
|
||||
d.bus.ReadRegister(d.Address, HTS221_CTRL1_REG, data)
|
||||
if data[0]&0x80 == 0 {
|
||||
return errors.New("device is off, unable to query")
|
||||
}
|
||||
|
||||
// wait until one shot (one conversion) is ready to go
|
||||
data[0] = 1
|
||||
for {
|
||||
d.bus.ReadRegister(d.Address, HTS221_CTRL2_REG, data)
|
||||
if data[0]&0x01 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// trigger one shot
|
||||
d.bus.WriteRegister(d.Address, HTS221_CTRL2_REG, []byte{0x01})
|
||||
|
||||
// wait until conversion completed
|
||||
data[0] = 0
|
||||
for {
|
||||
d.bus.ReadRegister(d.Address, HTS221_STATUS_REG, data)
|
||||
if data[0]&filter == filter {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readUint(msb byte, lsb byte) uint16 {
|
||||
return uint16(msb)<<8 | uint16(lsb)
|
||||
}
|
||||
|
||||
func readInt(msb byte, lsb byte) int16 {
|
||||
return int16(uint16(msb)<<8 | uint16(lsb))
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package hts221
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new HTS221 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package hts221
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new HTS221 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package hts221
|
||||
|
||||
const (
|
||||
|
||||
// I2C address
|
||||
HTS221_ADDRESS = 0x5F
|
||||
|
||||
// control/status registers
|
||||
HTS221_WHO_AM_I_REG = 0x0F
|
||||
HTS221_AV_CONF_REG = 0x10
|
||||
HTS221_CTRL1_REG = 0x20
|
||||
HTS221_CTRL2_REG = 0x21
|
||||
HTS221_STATUS_REG = 0x27
|
||||
HTS221_HUMID_OUT_REG = 0x28
|
||||
HTS221_TEMP_OUT_REG = 0x2A
|
||||
|
||||
// calibration registers
|
||||
HTS221_H0_rH_x2_REG = 0x30
|
||||
HTS221_H1_rH_x2_REG = 0x31
|
||||
HTS221_T0_degC_x8_REG = 0x32
|
||||
HTS221_T1_degC_x8_REG = 0x33
|
||||
HTS221_T1_T0_MSB_REG = 0x35
|
||||
HTS221_H0_T0_OUT_REG = 0x36
|
||||
HTS221_H1_T0_OUT_REG = 0x3A
|
||||
HTS221_T0_OUT_REG = 0x3C
|
||||
HTS221_T1_OUT_REG = 0x3E
|
||||
)
|
||||
@@ -0,0 +1,280 @@
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
)
|
||||
|
||||
// I2C is an I2C implementation by Software. Since it is implemented by
|
||||
// software, it can be used with microcontrollers that do not have I2C
|
||||
// function. This is not efficient but works around broken or missing drivers.
|
||||
type I2C struct {
|
||||
scl machine.Pin
|
||||
sda machine.Pin
|
||||
nack bool
|
||||
baudrate uint32
|
||||
}
|
||||
|
||||
// I2CConfig is used to store config info for I2C.
|
||||
type I2CConfig struct {
|
||||
Frequency uint32
|
||||
SCL machine.Pin
|
||||
SDA machine.Pin
|
||||
}
|
||||
|
||||
var (
|
||||
errSI2CAckExpected = errors.New("I2C error: expected ACK not NACK")
|
||||
)
|
||||
|
||||
// New returns the i2csoft driver. For the arguments, specify the pins to be
|
||||
// used as SCL and SDA. As I2C is implemented in software, any GPIO pin can be
|
||||
// specified.
|
||||
func New(sclPin, sdaPin machine.Pin) *I2C {
|
||||
return &I2C{
|
||||
scl: sclPin,
|
||||
sda: sdaPin,
|
||||
baudrate: 100e3,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure is intended to setup the I2C interface.
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
// Default I2C bus speed is 100 kHz.
|
||||
if config.Frequency != 0 {
|
||||
i2c.SetBaudRate(config.Frequency)
|
||||
}
|
||||
|
||||
// This exists for compatibility with machine.I2CConfig. SCL and SDA must
|
||||
// be set at the same time. Because Pin(0) is sometimes set, it is not
|
||||
// checked for 0.
|
||||
if config.SCL != config.SDA {
|
||||
i2c.scl = config.SCL
|
||||
i2c.sda = config.SDA
|
||||
}
|
||||
|
||||
// enable pins
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.sda.High()
|
||||
i2c.scl.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.scl.High()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBaudRate sets the communication speed for the I2C.
|
||||
func (i2c *I2C) SetBaudRate(br uint32) {
|
||||
// At this time, the value of i2c.baudrate is ignored because it is fixed
|
||||
// at 100 kHz. SetBaudrate() is exist for compatibility with machine.I2C.
|
||||
i2c.baudrate = br
|
||||
}
|
||||
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
|
||||
i2c.nack = false
|
||||
if len(w) != 0 {
|
||||
// send start/address for write
|
||||
i2c.sendAddress(addr, true)
|
||||
|
||||
// wait until transmission complete
|
||||
|
||||
// ACK received (0: ACK, 1: NACK)
|
||||
if i2c.nack {
|
||||
i2c.signalStop()
|
||||
return errSI2CAckExpected
|
||||
}
|
||||
|
||||
// write data
|
||||
for _, b := range w {
|
||||
i2c.writeByte(b)
|
||||
}
|
||||
|
||||
i2c.signalStop()
|
||||
}
|
||||
if len(r) != 0 {
|
||||
// send start/address for read
|
||||
i2c.sendAddress(addr, false)
|
||||
|
||||
// wait transmission complete
|
||||
|
||||
// ACK received (0: ACK, 1: NACK)
|
||||
if i2c.nack {
|
||||
i2c.signalStop()
|
||||
return errSI2CAckExpected
|
||||
}
|
||||
|
||||
// read first byte
|
||||
r[0] = i2c.readByte()
|
||||
for i := 1; i < len(r); i++ {
|
||||
// Send an ACK
|
||||
|
||||
i2c.signalRead()
|
||||
|
||||
// Read data and send the ACK
|
||||
r[i] = i2c.readByte()
|
||||
}
|
||||
|
||||
// Send NACK to end transmission
|
||||
i2c.sendNack()
|
||||
|
||||
i2c.signalStop()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeByte writes a single byte to the I2C bus.
|
||||
func (i2c *I2C) writeByte(data byte) {
|
||||
// Send data byte
|
||||
i2c.scl.Low()
|
||||
i2c.sda.High()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.wait()
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
i2c.scl.Low()
|
||||
if ((data >> (7 - i)) & 1) == 1 {
|
||||
i2c.sda.High()
|
||||
} else {
|
||||
i2c.sda.Low()
|
||||
}
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
|
||||
i2c.scl.Low()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
|
||||
i2c.nack = i2c.sda.Get()
|
||||
|
||||
i2c.wait()
|
||||
|
||||
// wait until transmission successful
|
||||
}
|
||||
|
||||
// sendAddress sends the address and start signal
|
||||
func (i2c *I2C) sendAddress(address uint16, write bool) {
|
||||
data := (address << 1)
|
||||
if !write {
|
||||
data |= 1 // set read flag
|
||||
}
|
||||
|
||||
i2c.scl.High()
|
||||
i2c.sda.Low()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
for i := 0; i < 8; i++ {
|
||||
i2c.scl.Low()
|
||||
if ((data >> (7 - i)) & 1) == 1 {
|
||||
i2c.sda.High()
|
||||
} else {
|
||||
i2c.sda.Low()
|
||||
}
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
|
||||
i2c.scl.Low()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
|
||||
i2c.nack = i2c.sda.Get()
|
||||
|
||||
i2c.wait()
|
||||
|
||||
// wait until bus ready
|
||||
}
|
||||
|
||||
func (i2c *I2C) signalStop() {
|
||||
i2c.scl.Low()
|
||||
i2c.sda.Low()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.sda.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
|
||||
func (i2c *I2C) signalRead() {
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.Low()
|
||||
i2c.sda.Low()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
|
||||
func (i2c *I2C) readByte() byte {
|
||||
var data byte
|
||||
for i := 0; i < 8; i++ {
|
||||
i2c.scl.Low()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
if i2c.sda.Get() {
|
||||
data |= 1 << (7 - i)
|
||||
}
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (i2c *I2C) sendNack() {
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.Low()
|
||||
i2c.sda.High()
|
||||
i2c.sda.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
i2c.scl.High()
|
||||
i2c.wait()
|
||||
i2c.wait()
|
||||
}
|
||||
|
||||
// WriteRegister transmits first the register and then the data to the
|
||||
// peripheral device.
|
||||
//
|
||||
// Many I2C-compatible devices are organized in terms of registers. This method
|
||||
// is a shortcut to easily write to such registers. Also, it only works for
|
||||
// devices with 7-bit addresses, which is the vast majority.
|
||||
func (i2c *I2C) WriteRegister(address uint8, register uint8, data []byte) error {
|
||||
buf := make([]uint8, len(data)+1)
|
||||
buf[0] = register
|
||||
copy(buf[1:], data)
|
||||
return i2c.Tx(uint16(address), buf, nil)
|
||||
}
|
||||
|
||||
// ReadRegister transmits the register, restarts the connection as a read
|
||||
// operation, and reads the response.
|
||||
//
|
||||
// Many I2C-compatible devices are organized in terms of registers. This method
|
||||
// is a shortcut to easily read such registers. Also, it only works for devices
|
||||
// with 7-bit addresses, which is the vast majority.
|
||||
func (i2c *I2C) ReadRegister(address uint8, register uint8, data []byte) error {
|
||||
return i2c.Tx(uint16(address), []byte{register}, data)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build atsamd51 || atsame5x
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval. It is set to
|
||||
// about 100 kHz.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 20
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build esp32
|
||||
// +build esp32
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval. It is set to
|
||||
// about 100 kHz.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 60
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build nrf52840
|
||||
// +build nrf52840
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval. It is set to
|
||||
// about 100 kHz.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 26
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !esp32 && !atsamd51 && !atsame5x && !stm32f4 && !rp2040 && !nrf52840
|
||||
// +build !esp32,!atsamd51,!atsame5x,!stm32f4,!rp2040,!nrf52840
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 20
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval. It is set to
|
||||
// about 100 kHz.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 50
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build stm32f4
|
||||
// +build stm32f4
|
||||
|
||||
package i2csoft
|
||||
|
||||
import (
|
||||
"device"
|
||||
)
|
||||
|
||||
// wait waits for half the time of the SCL operation interval. It is set to
|
||||
// about 100 kHz.
|
||||
func (i2c *I2C) wait() {
|
||||
wait := 77
|
||||
for i := 0; i < wait; i++ {
|
||||
device.Asm(`nop`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Package lps22hb implements a driver for LPS22HB, a MEMS nano pressure sensor.
|
||||
//
|
||||
// Datasheet: https://www.st.com/resource/en/datasheet/dm00140895.pdf
|
||||
//
|
||||
package lps22hb
|
||||
|
||||
import (
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a HTS221 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
}
|
||||
|
||||
// Connected returns whether LPS22HB has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_WHO_AM_I_REG, data)
|
||||
return data[0] == 0xB1
|
||||
}
|
||||
|
||||
// Configure sets up the LPS22HB device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// set to block update mode
|
||||
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in milli pascals (mPa).
|
||||
func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
d.waitForOneShot()
|
||||
|
||||
// read data
|
||||
data := []byte{0, 0, 0}
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+1, data[1:2])
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_PRESS_OUT_REG+2, data[2:])
|
||||
pValue := float32(uint32(data[2])<<16|uint32(data[1])<<8|uint32(data[0])) / 4096.0
|
||||
|
||||
return int32(pValue * 1000), nil
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
d.waitForOneShot()
|
||||
|
||||
// read data
|
||||
data := []byte{0, 0}
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG, data[:1])
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_TEMP_OUT_REG+1, data[1:])
|
||||
tValue := float32(int16(uint16(data[1])<<8|uint16(data[0]))) / 100.0
|
||||
|
||||
return int32(tValue * 1000), nil
|
||||
}
|
||||
|
||||
// private functions
|
||||
|
||||
// wait and trigger one shot in block update
|
||||
func (d *Device) waitForOneShot() {
|
||||
// trigger one shot
|
||||
d.bus.WriteRegister(d.Address, LPS22HB_CTRL2_REG, []byte{0x01})
|
||||
|
||||
// wait until one shot is cleared
|
||||
data := []byte{1}
|
||||
for {
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_CTRL2_REG, data)
|
||||
if data[0]&0x01 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package lps22hb
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new LPS22HB connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: LPS22HB_ADDRESS}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package lps22hb
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new LPS22HB connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
return Device{bus: bus, Address: LPS22HB_ADDRESS}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package lps22hb
|
||||
|
||||
const (
|
||||
|
||||
// I2C address
|
||||
LPS22HB_ADDRESS = 0x5C
|
||||
|
||||
// control/status registers
|
||||
LPS22HB_WHO_AM_I_REG = 0x0F
|
||||
LPS22HB_CTRL1_REG = 0x10
|
||||
LPS22HB_CTRL2_REG = 0x11
|
||||
LPS22HB_STATUS_REG = 0x27
|
||||
LPS22HB_PRESS_OUT_REG = 0x28
|
||||
LPS22HB_TEMP_OUT_REG = 0x2B
|
||||
)
|
||||
@@ -0,0 +1,227 @@
|
||||
// LSM9DS1, 9 axis Inertial Measurement Unit (IMU)
|
||||
//
|
||||
// Datasheet: https://www.st.com/resource/en/datasheet/lsm6ds3.pdf
|
||||
//
|
||||
package lsm9ds1 // import "tinygo.org/x/drivers/lsm9ds1"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type AccelRange uint8
|
||||
type AccelSampleRate uint8
|
||||
type AccelBandwidth uint8
|
||||
|
||||
type GyroRange uint8
|
||||
type GyroSampleRate uint8
|
||||
|
||||
type MagRange uint8
|
||||
type MagSampleRate uint8
|
||||
|
||||
// Device wraps connection to a LSM9DS1 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
AccelAddress uint8
|
||||
MagAddress uint8
|
||||
accelMultiplier int32
|
||||
gyroMultiplier int32
|
||||
magMultiplier int32
|
||||
dataBufferSix []uint8
|
||||
dataBufferTwo []uint8
|
||||
}
|
||||
|
||||
// Configuration for LSM9DS1 device.
|
||||
type Configuration struct {
|
||||
AccelRange AccelRange
|
||||
AccelSampleRate AccelSampleRate
|
||||
AccelBandWidth AccelBandwidth
|
||||
GyroRange GyroRange
|
||||
GyroSampleRate GyroSampleRate
|
||||
MagRange MagRange
|
||||
MagSampleRate MagSampleRate
|
||||
}
|
||||
|
||||
var errNotConnected = errors.New("lsm9ds1: failed to communicate with either acel/gyro or magnet sensor")
|
||||
|
||||
// New creates a new LSM9DS1 connection. The I2C bus must already be configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) *Device {
|
||||
return &Device{
|
||||
bus: bus,
|
||||
AccelAddress: ACCEL_ADDRESS,
|
||||
MagAddress: MAG_ADDRESS,
|
||||
dataBufferSix: make([]uint8, 6),
|
||||
dataBufferTwo: make([]uint8, 2),
|
||||
}
|
||||
}
|
||||
|
||||
// Connected returns whether both sensor on LSM9DS1 has been found.
|
||||
// It does two "who am I" requests and checks the responses.
|
||||
// In a rare case of an I2C bus issue, it can also return an error.
|
||||
// Case of boolean false and error nil means I2C is up,
|
||||
// but "who am I" responses have unexpected values.
|
||||
func (d *Device) Connected() (connected bool, err error) {
|
||||
data1, data2 := []byte{0}, []byte{0}
|
||||
err = d.bus.ReadRegister(d.AccelAddress, WHO_AM_I, data1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = d.bus.ReadRegister(d.MagAddress, WHO_AM_I_M, data2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return data1[0] == 0x68 && data2[0] == 0x3D, nil
|
||||
}
|
||||
|
||||
// ReadAcceleration reads the current acceleration from the device and returns
|
||||
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
|
||||
// and the sensor is not moving the returned value will be around 1000000 or
|
||||
// -1000000.
|
||||
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_XL, d.dataBufferSix)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
x = int32(int16((uint16(d.dataBufferSix[1])<<8)|uint16(d.dataBufferSix[0]))) * d.accelMultiplier
|
||||
y = int32(int16((uint16(d.dataBufferSix[3])<<8)|uint16(d.dataBufferSix[2]))) * d.accelMultiplier
|
||||
z = int32(int16((uint16(d.dataBufferSix[5])<<8)|uint16(d.dataBufferSix[4]))) * d.accelMultiplier
|
||||
return
|
||||
}
|
||||
|
||||
// ReadRotation reads the current rotation from the device and returns it in
|
||||
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
|
||||
// rotation along one axis and while doing so integrate all values over time,
|
||||
// you would get a value close to 360000000.
|
||||
func (d *Device) ReadRotation() (x, y, z int32, err error) {
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_X_L_G, d.dataBufferSix)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
x = int32(int16((uint16(d.dataBufferSix[1])<<8)|uint16(d.dataBufferSix[0]))) * d.gyroMultiplier
|
||||
y = int32(int16((uint16(d.dataBufferSix[3])<<8)|uint16(d.dataBufferSix[2]))) * d.gyroMultiplier
|
||||
z = int32(int16((uint16(d.dataBufferSix[5])<<8)|uint16(d.dataBufferSix[4]))) * d.gyroMultiplier
|
||||
return
|
||||
}
|
||||
|
||||
// ReadMagneticField reads the current magnetic field from the device and returns
|
||||
// it in nT (nanotesla). 1 G (gauss) = 100_000 nT (nanotesla).
|
||||
func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
|
||||
err = d.bus.ReadRegister(uint8(d.MagAddress), OUT_X_L_M, d.dataBufferSix)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
x = int32(int16((int16(d.dataBufferSix[1])<<8)|int16(d.dataBufferSix[0]))) * d.magMultiplier
|
||||
y = int32(int16((int16(d.dataBufferSix[3])<<8)|int16(d.dataBufferSix[2]))) * d.magMultiplier
|
||||
z = int32(int16((int16(d.dataBufferSix[5])<<8)|int16(d.dataBufferSix[4]))) * d.magMultiplier
|
||||
return
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in Celsius milli degrees (°C/1000)
|
||||
func (d *Device) ReadTemperature() (t int32, err error) {
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_L, d.dataBufferTwo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// From "Table 5. Temperature sensor characteristics"
|
||||
// temp = value/16 + 25
|
||||
t = 25000 + (int32(int16((int16(d.dataBufferTwo[1])<<8)|int16(d.dataBufferTwo[0])))*125)/2
|
||||
return
|
||||
}
|
||||
|
||||
// --- end of public methods --------------------------------------------------
|
||||
|
||||
// doConfigure is called by public Configure methods after all
|
||||
// necessary board-specific initialisations are taken care of
|
||||
func (d *Device) doConfigure(cfg Configuration) (err error) {
|
||||
|
||||
// Verify unit communication
|
||||
if con, err := d.Connected(); !con || err != nil {
|
||||
return errNotConnected
|
||||
}
|
||||
|
||||
// Multipliers come from "Table 3. Sensor characteristics" of the datasheet * 1000
|
||||
switch cfg.AccelRange {
|
||||
case ACCEL_2G:
|
||||
d.accelMultiplier = 61
|
||||
case ACCEL_4G:
|
||||
d.accelMultiplier = 122
|
||||
case ACCEL_8G:
|
||||
d.accelMultiplier = 244
|
||||
case ACCEL_16G:
|
||||
d.accelMultiplier = 732
|
||||
}
|
||||
switch cfg.GyroRange {
|
||||
case GYRO_250DPS:
|
||||
d.gyroMultiplier = 8750
|
||||
case GYRO_500DPS:
|
||||
d.gyroMultiplier = 17500
|
||||
case GYRO_2000DPS:
|
||||
d.gyroMultiplier = 70000
|
||||
}
|
||||
switch cfg.MagRange {
|
||||
case MAG_4G:
|
||||
d.magMultiplier = 14
|
||||
case MAG_8G:
|
||||
d.magMultiplier = 29
|
||||
case MAG_12G:
|
||||
d.magMultiplier = 43
|
||||
case MAG_16G:
|
||||
d.magMultiplier = 58
|
||||
}
|
||||
|
||||
data := make([]byte, 1)
|
||||
|
||||
// Configure accelerometer
|
||||
// Sample rate & measurement range
|
||||
data[0] = uint8(cfg.AccelSampleRate)<<5 | uint8(cfg.AccelRange)<<3
|
||||
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG6_XL, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Configure gyroscope
|
||||
// Sample rate & measurement range
|
||||
data[0] = uint8(cfg.GyroSampleRate)<<5 | uint8(cfg.GyroRange)<<3
|
||||
err = d.bus.WriteRegister(d.AccelAddress, CTRL_REG1_G, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Configure magnetometer
|
||||
|
||||
// Temperature compensation enabled
|
||||
// High-performance mode XY axis
|
||||
// Sample rate
|
||||
data[0] = 0b10000000 | 0b01000000 | uint8(cfg.MagSampleRate)<<2
|
||||
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG1_M, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Measurement range
|
||||
data[0] = uint8(cfg.MagRange) << 5
|
||||
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG2_M, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Continuous-conversion mode
|
||||
// https://electronics.stackexchange.com/questions/237397/continuous-conversion-vs-single-conversion-mode
|
||||
data[0] = 0b00000000
|
||||
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG3_M, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// High-performance mode Z axis
|
||||
data[0] = 0b00001000
|
||||
err = d.bus.WriteRegister(d.MagAddress, CTRL_REG4_M, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package lsm9ds1
|
||||
|
||||
// Configure sets up the device for communication.
|
||||
func (d *Device) Configure(cfg Configuration) error {
|
||||
return d.doConfigure(cfg)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
// Nano 33 BLE [Sense] has LSM9DS1 unit on-board.
|
||||
// This custom Configure function powers unit up
|
||||
// and enables I2C, so unit can can be accessed.
|
||||
package lsm9ds1
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Configure sets up the device for communication.
|
||||
func (d *Device) Configure(cfg Configuration) error {
|
||||
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
|
||||
machine.LSM_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.LSM_PWR.High()
|
||||
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.I2C_PULLUP.High()
|
||||
// Wait a moment
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Common initialisation code
|
||||
return d.doConfigure(cfg)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package lsm9ds1
|
||||
|
||||
// Constants/addresses used for I2C.
|
||||
|
||||
const (
|
||||
|
||||
// Constants/addresses used for I2C.
|
||||
ACCEL_ADDRESS = 0x6B
|
||||
MAG_ADDRESS = 0x1E
|
||||
|
||||
// Table 21. Accelerometer and gyroscope register address map
|
||||
WHO_AM_I = 0x0F // value 0x68
|
||||
CTRL_REG1_G = 0x10
|
||||
OUT_X_L_G = 0x18
|
||||
OUT_X_H_G = 0x19
|
||||
OUT_Y_L_G = 0x1A
|
||||
OUT_Y_H_G = 0x1B
|
||||
OUT_Z_L_G = 0x1C
|
||||
OUT_Z_H_G = 0x1D
|
||||
OUT_TEMP_L = 0x15
|
||||
OUT_TEMP_H = 0x16
|
||||
CTRL_REG6_XL = 0x20
|
||||
STATUS_REG = 0x27
|
||||
OUT_X_L_XL = 0x28
|
||||
OUT_X_H_XL = 0x29
|
||||
OUT_Y_L_XL = 0x2A
|
||||
OUT_Y_H_XL = 0x2B
|
||||
OUT_Z_L_XL = 0x2C
|
||||
OUT_Z_H_XL = 0x2D
|
||||
|
||||
// Table 22. Magnetic sensor register address map
|
||||
OFFSET_X_REG_L_M = 0x05
|
||||
OFFSET_X_REG_H_M = 0x06
|
||||
OFFSET_Y_REG_L_M = 0x07
|
||||
OFFSET_Y_REG_H_M = 0x08
|
||||
OFFSET_Z_REG_L_M = 0x09
|
||||
OFFSET_Z_REG_H_M = 0x0A
|
||||
WHO_AM_I_M = 0x0F // value 0x3D
|
||||
CTRL_REG1_M = 0x20 // TEMP_COMP OM1 OM0 DO2 DO1 DO0 FAST_ODR ST
|
||||
CTRL_REG2_M = 0x21 // 0 FS1 FS0 0 REBOOT SOFT_RST 0 0
|
||||
CTRL_REG3_M = 0x22 // 0 LP 0 0 SIM MD1 MD0
|
||||
CTRL_REG4_M = 0x23 // 0 0 0 0 OMZ1 OMZ0 BLE 0
|
||||
STATUS_REG_M = 0x27
|
||||
OUT_X_L_M = 0x28
|
||||
OUT_X_H_M = 0x29
|
||||
OUT_Y_L_M = 0x2A
|
||||
OUT_Y_H_M = 0x2B
|
||||
OUT_Z_L_M = 0x2C
|
||||
OUT_Z_H_M = 0x2D
|
||||
|
||||
// Table 67. CTRL_REG6_XL register description
|
||||
ACCEL_2G AccelRange = 0b00
|
||||
ACCEL_4G AccelRange = 0b10
|
||||
ACCEL_8G AccelRange = 0b11
|
||||
ACCEL_16G AccelRange = 0b01
|
||||
|
||||
// Table 68. ODR register setting (accelerometer only mode)
|
||||
ACCEL_SR_OFF AccelSampleRate = 0b000
|
||||
ACCEL_SR_10 AccelSampleRate = 0b001
|
||||
ACCEL_SR_50 AccelSampleRate = 0b010
|
||||
ACCEL_SR_119 AccelSampleRate = 0b011
|
||||
ACCEL_SR_238 AccelSampleRate = 0b100
|
||||
ACCEL_SR_476 AccelSampleRate = 0b101
|
||||
ACCEL_SR_952 AccelSampleRate = 0b110
|
||||
|
||||
// Table 67. CTRL_REG6_XL register description
|
||||
ACCEL_BW_50 AccelBandwidth = 0b11
|
||||
ACCEL_BW_105 AccelBandwidth = 0b10
|
||||
ACCEL_BW_211 AccelBandwidth = 0b01
|
||||
ACCEL_BW_408 AccelBandwidth = 0b00
|
||||
|
||||
// Table 45. CTRL_REG1_G register description
|
||||
GYRO_250DPS GyroRange = 0b00
|
||||
GYRO_500DPS GyroRange = 0b01
|
||||
GYRO_2000DPS GyroRange = 0b11
|
||||
|
||||
// Table 9. Gyroscope operating modes
|
||||
// Table 46. ODR and BW configuration setting (after LPF1)
|
||||
GYRO_SR_OFF GyroSampleRate = 0b000
|
||||
GYRO_SR_15 GyroSampleRate = 0b001
|
||||
GYRO_SR_60 GyroSampleRate = 0b010
|
||||
GYRO_SR_119 GyroSampleRate = 0b011
|
||||
GYRO_SR_238 GyroSampleRate = 0b100
|
||||
GYRO_SR_476 GyroSampleRate = 0b101
|
||||
GYRO_SR_952 GyroSampleRate = 0b110
|
||||
|
||||
// Table 114. Full-scale selection
|
||||
MAG_4G MagRange = 0b00
|
||||
MAG_8G MagRange = 0b01
|
||||
MAG_12G MagRange = 0b10
|
||||
MAG_16G MagRange = 0b11
|
||||
|
||||
// Table 111. Output data rate configuration
|
||||
MAG_SR_06 MagSampleRate = 0b000
|
||||
MAG_SR_1 MagSampleRate = 0b001
|
||||
MAG_SR_2 MagSampleRate = 0b010
|
||||
MAG_SR_5 MagSampleRate = 0b011
|
||||
MAG_SR_10 MagSampleRate = 0b100
|
||||
MAG_SR_20 MagSampleRate = 0b101
|
||||
MAG_SR_40 MagSampleRate = 0b110
|
||||
MAG_SR_80 MagSampleRate = 0b111
|
||||
)
|
||||
+1
-1
@@ -83,7 +83,7 @@ func (p ADCPin) Get() uint16 {
|
||||
p.d.bus.Tx(p.d.tx, p.d.rx)
|
||||
|
||||
// scale result to 16bit value like other ADCs
|
||||
result := uint16((p.d.rx[1]&0x3))<<8 + uint16(p.d.rx[2])<<6
|
||||
result := uint16((p.d.rx[1]&0x3))<<(8+6) + uint16(p.d.rx[2])<<6
|
||||
p.d.cs.High()
|
||||
|
||||
return result
|
||||
|
||||
+1
-1
@@ -186,7 +186,7 @@ func (c *TCPSerialConn) LocalAddr() Addr {
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (c *TCPSerialConn) RemoteAddr() Addr {
|
||||
return c.laddr.opAddr()
|
||||
return c.raddr.opAddr()
|
||||
}
|
||||
|
||||
func (c *TCPSerialConn) opConn() Conn {
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// series by Sensirion.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf
|
||||
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf
|
||||
//
|
||||
package sht3x // import "tinygo.org/x/drivers/sht3x"
|
||||
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@ package drivers
|
||||
|
||||
// Version returns a user-readable string showing the version of the drivers package for support purposes.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.17.1"
|
||||
const Version = "0.18.0"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package wifinina
|
||||
|
||||
import "errors"
|
||||
|
||||
// Mimics machine package's pin control
|
||||
//
|
||||
// NB! These are NINA chip pins, not main unit pins.
|
||||
//
|
||||
// Digital pin values and modes taken from
|
||||
// https://github.com/arduino/nina-fw/blob/master/arduino/cores/esp32/wiring_digital.h
|
||||
|
||||
type Pin uint8
|
||||
|
||||
const (
|
||||
PinLow uint8 = iota
|
||||
PinHigh
|
||||
)
|
||||
|
||||
type PinMode uint8
|
||||
|
||||
const (
|
||||
PinInput PinMode = iota
|
||||
PinOutput
|
||||
PinInputPullup
|
||||
)
|
||||
|
||||
type PinConfig struct {
|
||||
Mode PinMode
|
||||
}
|
||||
|
||||
var (
|
||||
ErrPinNoDevice = errors.New("wifinina pin: device not set")
|
||||
)
|
||||
|
||||
var pinDevice *Device
|
||||
|
||||
func pinUseDevice(d *Device) {
|
||||
pinDevice = d
|
||||
}
|
||||
|
||||
func (p Pin) Configure(config PinConfig) error {
|
||||
if pinDevice == nil {
|
||||
return ErrPinNoDevice
|
||||
}
|
||||
return pinDevice.PinMode(uint8(p), uint8(config.Mode))
|
||||
}
|
||||
|
||||
func (p Pin) Set(high bool) error {
|
||||
if pinDevice == nil {
|
||||
return ErrPinNoDevice
|
||||
}
|
||||
value := PinLow
|
||||
if high {
|
||||
value = PinHigh
|
||||
}
|
||||
return pinDevice.DigitalWrite(uint8(p), value)
|
||||
}
|
||||
|
||||
func (p Pin) High() error {
|
||||
return p.Set(true)
|
||||
}
|
||||
|
||||
func (p Pin) Low() error {
|
||||
return p.Set(false)
|
||||
}
|
||||
@@ -297,6 +297,7 @@ func New(bus drivers.SPI, csPin, ackPin, gpio0Pin, resetPin machine.Pin) *Device
|
||||
func (d *Device) Configure() {
|
||||
|
||||
net.UseDriver(d.NewDriver())
|
||||
pinUseDevice(d)
|
||||
|
||||
d.CS.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
d.ACK.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
@@ -689,6 +690,23 @@ func (d *Device) StartScanNetworks() (uint8, error) {
|
||||
return d.getUint8(d.req0(CmdStartScanNetworks))
|
||||
}
|
||||
|
||||
func (d *Device) PinMode(pin uint8, mode uint8) error {
|
||||
_, err := d.req2Uint8(CmdSetPinMode, pin, mode)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Device) DigitalWrite(pin uint8, value uint8) error {
|
||||
_, err := d.req2Uint8(CmdSetDigitalWrite, pin, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Device) AnalogWrite(pin uint8, value uint8) error {
|
||||
_, err := d.req2Uint8(CmdSetAnalogWrite, pin, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// ------------- End of public device interface ----------------------------
|
||||
|
||||
func (d *Device) getString(l uint8, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -773,6 +791,14 @@ func (d *Device) reqUint8(cmd uint8, data uint8) (l uint8, err error) {
|
||||
return d.waitRspCmd1(cmd)
|
||||
}
|
||||
|
||||
// req2Uint8 sends a command to the device with two uint8 parameters
|
||||
func (d *Device) req2Uint8(cmd, p1, p2 uint8) (l uint8, err error) {
|
||||
if err := d.sendCmdPadded2(cmd, p1, p2); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.waitRspCmd1(cmd)
|
||||
}
|
||||
|
||||
// reqStr sends a command to the device with a single string parameter
|
||||
func (d *Device) reqStr(cmd uint8, p1 string) (uint8, error) {
|
||||
if err := d.sendCmdStr(cmd, p1); err != nil {
|
||||
@@ -834,6 +860,18 @@ func (d *Device) sendCmdPadded1(cmd uint8, data uint8) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Device) sendCmdPadded2(cmd, data1, data2 uint8) error {
|
||||
defer d.spiChipDeselect()
|
||||
if err := d.waitForChipSelect(); err != nil {
|
||||
return err
|
||||
}
|
||||
l := d.sendCmd(cmd, 1)
|
||||
l += d.sendParam8(data1, false)
|
||||
l += d.sendParam8(data2, true)
|
||||
d.SPI.Transfer(dummyData)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Device) sendCmdStr(cmd uint8, p1 string) (err error) {
|
||||
defer d.spiChipDeselect()
|
||||
if err := d.waitForChipSelect(); err != nil {
|
||||
|
||||
@@ -5,9 +5,11 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -34,10 +36,77 @@ import (
|
||||
// The timings deviate a little bit from the code here, but so far the timings
|
||||
// from wp.josh.com seem to be fine for the ws2812.
|
||||
|
||||
// Clock frequencies to support, in MHz.
|
||||
var clockFrequencies = []int{16, 48, 64, 120, 168}
|
||||
// Architecture implementation. Describes the template and the timings of the
|
||||
// blocks of instructions so that most code can remain architecture-independent.
|
||||
type architectureImpl struct {
|
||||
buildTag string
|
||||
minBaseCyclesT0H int
|
||||
maxBaseCyclesT0H int
|
||||
minBaseCyclesT1H int
|
||||
maxBaseCyclesT1H int
|
||||
minBaseCyclesTLD int
|
||||
valueTemplate string // template for how to pass the 'c' byte to assembly
|
||||
template string // assembly template
|
||||
}
|
||||
|
||||
func writeImplementation(f *os.File, megahertz int) error {
|
||||
var architectures = map[string]architectureImpl{
|
||||
"cortexm": {
|
||||
// Assume that a branch is 1 to 3 cycles, no matter whether it's taken
|
||||
// or not. This is a rather conservative estimate, for Cortex-M+ for
|
||||
// example the instruction cycles are precisely known.
|
||||
buildTag: "cortexm",
|
||||
minBaseCyclesT0H: 1 + 1 + 2, // shift + branch (not taken) + store
|
||||
maxBaseCyclesT0H: 1 + 3 + 2, // shift + branch (not taken) + store
|
||||
minBaseCyclesT1H: 1 + 1 + 2, // shift + branch (taken) + store
|
||||
maxBaseCyclesT1H: 1 + 3 + 2, // shift + branch (taken) + store
|
||||
minBaseCyclesTLD: 1 + 1 + 2, // subtraction + branch + store (in next cycle)
|
||||
valueTemplate: "uint32(c) << 24",
|
||||
template: `
|
||||
1: @ send_bit
|
||||
str {maskSet}, {portSet} @ [2] T0H and T0L start here
|
||||
@DELAY1
|
||||
lsls {value}, #1 @ [1]
|
||||
bcs.n 2f @ [1/3] skip_store
|
||||
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
|
||||
2: @ skip_store
|
||||
@DELAY2
|
||||
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
|
||||
@DELAY3
|
||||
subs {i}, #1 @ [1]
|
||||
bne.n 1b @ [1/3] send_bit
|
||||
`,
|
||||
},
|
||||
"tinygoriscv": {
|
||||
// Largely based on the SiFive FE310 CPU:
|
||||
// - stores are 1 cycle
|
||||
// - branches are 1 or 3 cycles, depending on branch prediction
|
||||
// - ALU operations are 1 cycle (as on most CPUs)
|
||||
// Hopefully this generalizes to other chips.
|
||||
buildTag: "tinygo.riscv32",
|
||||
minBaseCyclesT0H: 1 + 1 + 1, // shift + branch (not taken) + store
|
||||
maxBaseCyclesT0H: 1 + 3 + 1, // shift + branch (not taken) + store
|
||||
minBaseCyclesT1H: 1 + 1 + 1, // shift + branch (taken) + store
|
||||
maxBaseCyclesT1H: 1 + 3 + 1, // shift + branch (taken) + store
|
||||
minBaseCyclesTLD: 1 + 1 + 1, // subtraction + branch + store (in next cycle)
|
||||
valueTemplate: "uint32(c) << 23",
|
||||
template: `
|
||||
1: // send_bit
|
||||
sw {maskSet}, {portSet} // [1] T0H and T0L start here
|
||||
@DELAY1
|
||||
slli {value}, {value}, 1 // [1] shift value left by 1
|
||||
bltz {value}, 2f // [1/3] skip_store
|
||||
sw {maskClear}, {portClear} // [1] T0H -> T0L transition
|
||||
2: // skip_store
|
||||
@DELAY2
|
||||
sw {maskClear}, {portClear} // [1] T1H -> T1L transition
|
||||
@DELAY3
|
||||
addi {i}, {i}, -1 // [1]
|
||||
bnez {i}, 1b // [1/3] send_bit
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
func writeImplementation(f *os.File, arch string, megahertz int) error {
|
||||
cycleTimeNS := 1 / float64(megahertz)
|
||||
// These timings are taken from the table "Updated simplified timing
|
||||
// constraints for NeoPixel strings" at:
|
||||
@@ -72,7 +141,7 @@ func writeImplementation(f *os.File, megahertz int) error {
|
||||
maxCyclesT1H := int(math.Floor(5.500 / cycleTimeNS))
|
||||
minCyclesTLD := int(math.Ceil(1.150 / cycleTimeNS))
|
||||
|
||||
// Assembly template:
|
||||
// The assembly template looks something like this:
|
||||
// 1: @ send_bit
|
||||
// str {maskSet}, {portSet} @ [2] T0H and T0L start here
|
||||
// ...delay 1
|
||||
@@ -87,29 +156,31 @@ func writeImplementation(f *os.File, megahertz int) error {
|
||||
// bne.n 1b @ [1/3] send_bit
|
||||
//
|
||||
// We need to calculate the number of nop instructions in the three delays.
|
||||
archImpl, ok := architectures[arch]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown architecture: %s", arch)
|
||||
}
|
||||
|
||||
// Determine number of nops for delay1. This is primarily based on the T0H
|
||||
// delay, which is relatively short (<500ns).
|
||||
minBaseCyclesT0H := 1 + 1 + 2 // shift + branch + store
|
||||
maxBaseCyclesT0H := 1 + 3 + 2 // shift + branch + store
|
||||
delay1 := minCyclesT0H - minBaseCyclesT0H
|
||||
delay1 := minCyclesT0H - archImpl.minBaseCyclesT0H
|
||||
if delay1 < 0 {
|
||||
// The minCyclesT0H constraint could not be satisfied. Don't insert
|
||||
// nops, in the hope that it isn't too long.
|
||||
delay1 = 0
|
||||
}
|
||||
if delay1+maxBaseCyclesT0H > maxCyclesT0H {
|
||||
if delay1+archImpl.maxBaseCyclesT0H > maxCyclesT0H {
|
||||
return fmt.Errorf("MCU appears to be too slow to satisfy minimum requirements for the T0H signal")
|
||||
}
|
||||
actualMinCyclesT0H := minBaseCyclesT0H + delay1
|
||||
actualMaxCyclesT0H := maxBaseCyclesT0H + delay1
|
||||
actualMinCyclesT0H := archImpl.minBaseCyclesT0H + delay1
|
||||
actualMaxCyclesT0H := archImpl.maxBaseCyclesT0H + delay1
|
||||
actualMinNanosecondsT0H := float64(actualMinCyclesT0H) / float64(megahertz) * 1000
|
||||
actualMaxNanosecondsT0H := float64(actualMaxCyclesT0H) / float64(megahertz) * 1000
|
||||
|
||||
// Determine number of nops for delay2. This is delay1 plus some extra time
|
||||
// so that the pulse is long enough for T1H.
|
||||
minBaseCyclesT1H := delay1 + 1 + 1 + 2 // delay1 + shift + branch + store
|
||||
maxBaseCyclesT1H := delay1 + 1 + 3 + 2 // delay1 + shift + branch + store
|
||||
minBaseCyclesT1H := delay1 + archImpl.minBaseCyclesT1H // delay1 + asssembly cycles
|
||||
maxBaseCyclesT1H := delay1 + archImpl.maxBaseCyclesT1H // delay1 + asssembly cycles
|
||||
delay2 := minCyclesT1H - minBaseCyclesT1H
|
||||
if delay2 < 0 {
|
||||
delay2 = 0
|
||||
@@ -125,12 +196,11 @@ func writeImplementation(f *os.File, megahertz int) error {
|
||||
|
||||
// Determine number of nops for delay3. This is based on the TLD delay, the
|
||||
// time between two high pulses.
|
||||
minBaseCyclesTLD := 1 + 1 + 2 // subtraction + branch + store (in next cycle)
|
||||
delay3 := minCyclesTLD - minBaseCyclesTLD
|
||||
delay3 := minCyclesTLD - archImpl.minBaseCyclesTLD
|
||||
if delay3 < 0 {
|
||||
delay3 = 0
|
||||
}
|
||||
actualMinCyclesTLD := minBaseCyclesTLD + delay3
|
||||
actualMinCyclesTLD := archImpl.minBaseCyclesTLD + delay3
|
||||
actualMinNanosecondsTLD := float64(actualMinCyclesTLD) / float64(megahertz) * 1000
|
||||
|
||||
// Create the Go function in a buffer. Using a buffer here to be able to
|
||||
@@ -146,21 +216,13 @@ func writeImplementation(f *os.File, megahertz int) error {
|
||||
fmt.Fprintf(buf, " // T1H: %2d - %2d cycles or %.1fns - %.1fns\n", actualMinCyclesT1H, actualMaxCyclesT1H, actualMinNanosecondsT1H, actualMaxNanosecondsT1H)
|
||||
fmt.Fprintf(buf, " // TLD: %2d - cycles or %.1fns -\n", actualMinCyclesTLD, actualMinNanosecondsTLD)
|
||||
fmt.Fprintf(buf, " mask := interrupt.Disable()\n")
|
||||
fmt.Fprintf(buf, " value := uint32(c) << 24\n")
|
||||
fmt.Fprintf(buf, " device.AsmFull(`\n")
|
||||
fmt.Fprintf(buf, " 1: @ send_bit\n")
|
||||
fmt.Fprintf(buf, " str {maskSet}, {portSet} @ [2] T0H and T0L start here\n")
|
||||
buf.WriteString(strings.Repeat(" nop\n", delay1))
|
||||
fmt.Fprintf(buf, " lsls {value}, #1 @ [1]\n")
|
||||
fmt.Fprintf(buf, " bcs.n 2f @ [1/3] skip_store\n")
|
||||
fmt.Fprintf(buf, " str {maskClear}, {portClear} @ [2] T0H -> T0L transition\n")
|
||||
fmt.Fprintf(buf, " 2: @ skip_store\n")
|
||||
buf.WriteString(strings.Repeat(" nop\n", delay2))
|
||||
fmt.Fprintf(buf, " str {maskClear}, {portClear} @ [2] T1H -> T1L transition\n")
|
||||
buf.WriteString(strings.Repeat(" nop\n", delay3))
|
||||
fmt.Fprintf(buf, " subs {i}, #1 @ [1]\n")
|
||||
fmt.Fprintf(buf, " bne.n 1b @ [1/3] send_bit\n")
|
||||
fmt.Fprintf(buf, " `, map[string]interface{}{")
|
||||
fmt.Fprintf(buf, " value := %s\n", archImpl.valueTemplate)
|
||||
asm := archImpl.template
|
||||
asm = strings.ReplaceAll(asm, " @DELAY1\n", strings.Repeat(" nop\n", delay1))
|
||||
asm = strings.ReplaceAll(asm, " @DELAY2\n", strings.Repeat(" nop\n", delay2))
|
||||
asm = strings.ReplaceAll(asm, " @DELAY3\n", strings.Repeat(" nop\n", delay3))
|
||||
asm = strings.ReplaceAll(asm, "\n", "\n\t")
|
||||
fmt.Fprintf(buf, " device.AsmFull(`%s`, map[string]interface{}{", asm)
|
||||
buf.WriteString(`
|
||||
"value": value,
|
||||
"i": 8,
|
||||
@@ -179,19 +241,33 @@ func writeImplementation(f *os.File, megahertz int) error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
f, err := os.Create("ws2812-asm_cortexm.go")
|
||||
arch := flag.String("arch", "cortexm", "architecture to output to")
|
||||
flag.Parse()
|
||||
|
||||
// Remaining parameters are all clock frequencies.
|
||||
var clockFrequencies []int
|
||||
for _, s := range flag.Args() {
|
||||
freq, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "cannot parse frequency:", s)
|
||||
os.Exit(1)
|
||||
}
|
||||
clockFrequencies = append(clockFrequencies, freq)
|
||||
}
|
||||
|
||||
f, err := os.Create("ws2812-asm_" + *arch + ".go")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "could not generate WS2812 assembly code:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
f.WriteString(`//go:build cortexm
|
||||
// +build cortexm
|
||||
|
||||
fmt.Fprintln(f, "//go:build", architectures[*arch].buildTag)
|
||||
fmt.Fprintln(f, "// +build", architectures[*arch].buildTag)
|
||||
f.WriteString(`
|
||||
package ws2812
|
||||
|
||||
// Warning: autogenerated file. Instead of modifying this file, change
|
||||
// gen-ws2812-arm.go and run "go generate".
|
||||
// gen-ws2812.go and run "go generate".
|
||||
|
||||
import (
|
||||
"device"
|
||||
@@ -199,9 +275,9 @@ import (
|
||||
)
|
||||
`)
|
||||
for _, megahertz := range clockFrequencies {
|
||||
err := writeImplementation(f, megahertz)
|
||||
err := writeImplementation(f, *arch, megahertz)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not generate WS2812 assembly code for %dMHz: %s\n", megahertz, err)
|
||||
fmt.Fprintf(os.Stderr, "could not generate WS2812 assembly code for %s and %dMHz: %s\n", *arch, megahertz, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
package ws2812
|
||||
|
||||
// Warning: autogenerated file. Instead of modifying this file, change
|
||||
// gen-ws2812-arm.go and run "go generate".
|
||||
// gen-ws2812.go and run "go generate".
|
||||
|
||||
import (
|
||||
"device"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -1,7 +1,8 @@
|
||||
// Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips.
|
||||
package ws2812 // import "tinygo.org/x/drivers/ws2812"
|
||||
|
||||
//go:generate go run gen-ws2812-arm.go
|
||||
//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 168
|
||||
//go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//go:build tinygo.riscv32
|
||||
// +build tinygo.riscv32
|
||||
|
||||
package ws2812
|
||||
|
||||
import "machine"
|
||||
|
||||
// Send a single byte using the WS2812 protocol.
|
||||
func (d Device) WriteByte(c byte) error {
|
||||
switch machine.CPUFrequency() {
|
||||
case 160_000_000: // 160MHz, e.g. esp32c3
|
||||
d.writeByte160(c)
|
||||
return nil
|
||||
case 320_000_000: // 320MHz, e.g. fe310
|
||||
d.writeByte320(c)
|
||||
return nil
|
||||
default:
|
||||
return errUnknownClockSpeed
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user