Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem f367eabcf4 ws2812: add SPI based implementation
This is useful because it allows using the WS2812 driver on platforms
without bitbanged WS2812 support and it may be the only option if
disabling interrupts is impossible or impractical.
2020-12-27 00:37:09 +01:00
147 changed files with 2008 additions and 11461 deletions
-1
View File
@@ -1,2 +1 @@
build
.vscode/
-65
View File
@@ -1,68 +1,3 @@
0.16.0
---
- **new devices**
- aht20: add device
- ina260: add new i2c device
- keypad: add 4x4 keypad driver (#226)
- max7219: add driver support
- mcp2515: add support for mcp2515 CAN device
- p1am: support the P1AM-100 hardware watchdog
- pcf8563: add support for pcf8563 real time clock
- servo: add driver using PWM
- tm1637: add support for tm1637 7-segment LED
- tone: add package for producing tones using the PWM interface
- **enhancements**
- pwm: update drivers with PWM to use new interface
- wifinina: Make TLS work over WiFiNINA Verified on Arduino Nano33 IoT and nina fw v1.4.5
- ssd1306: Enable reset screen for SSD1306 via I2C
- st7789: add scrolling functions to match st7735
- **bugfixes**
- wifinina:
- fix getMACAddress and getTime
- fix println + cleanup
- remove debug flag and remove unnecessary padding call
- fix padding and implement missing functions
- flash: fix EraseBlocks method which is erasing sectors instead
- **core**
- all: use interfaces for UART objects
- all: do not take the pointer of an I2C object
- adc: update drivers with ADC to use new config struct
- **testing**
- tester:
- add a mock for command-oriented i2c devices
- add 16-bit register mock device
- **docs**
- ssd1306: example of ssd1306 with 128x64 display over I2C
- wifinina:
- add information about Adafruit boards with ESP32 wifi coprocessors, and modify examples to remove code that was both not being used, and also prevented many Adafruit boards from being able to be targeted by the examples
- update docs to simplify the nina-fw update process
- example that connects to AP and prints ip addresses, time and mac
- p1am: documentation and example program
- add missing new drivers added since last release
0.15.0
---
- **new devices**
- dht: add DHTXX thermometer
- mcp23017: new driver for MCP23017 (I2C port expander)
- bmp388: Add bmp388 support (#219)
- **enhancements**
- hd44780: add a mode to work with boards where the RW pin is grounded
- st7789: add scrolling functions to match st7735
- microbitmatrix: matrix now working on microbit v2
- ds1307: Better interface "ReadTime" instead of "Time"
- ws2812: make AVR support more robust
- **bugfixes**
- all: fix main package in examples
- **core**
- adc: update all drivers with ADC to use new config struct
- spi: remove machine.SPI and replace with drivers.SPI interface for almost all SPI drivers
- **testing**
- test: run unit tests against i2c drivers and any spi drivers without direct gpio
- **docs**
- st7789: correct errors on various godoc comments
0.14.0
---
- **new devices**
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2021 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2020 The TinyGo Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
+1 -40
View File
@@ -31,8 +31,6 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp280/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bmp388/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/sram/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/time/main.go
@@ -83,28 +81,18 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017-multiple/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp2515/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mpu6050/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
@@ -121,10 +109,6 @@ smoke-test:
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/thermistor/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=circuitplay-bluefruit ./examples/tone
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/tm1637/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/fourwire/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/pyportal_touchpaint/main.go
@@ -175,34 +159,11 @@ endif
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/max72xx/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/time/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/tinyfs/
@md5sum ./build/test.hex
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
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
unit-test:
+2 -15
View File
@@ -3,7 +3,7 @@
[![PkgGoDev](https://pkg.go.dev/badge/tinygo.org/x/drivers)](https://pkg.go.dev/tinygo.org/x/drivers) [![CircleCI](https://circleci.com/gh/tinygo-org/drivers/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/drivers/tree/dev)
This package provides a collection of hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
This package provides a collection of hardware drivers for devices that can be used together with [TinyGo](https://tinygo.org).
## Installing
@@ -52,13 +52,12 @@ func main() {
## Currently supported devices
The following 66 devices are supported.
The following 53 devices are supported.
| Device Name | Interface Type |
|----------|-------------|
| [ADT7410 I2C Temperature Sensor](https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf) | I2C |
| [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C |
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
@@ -69,9 +68,7 @@ The following 66 devices are supported.
| [BMI160 accelerometer/gyroscope](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi160-ds000.pdf) | SPI |
| [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C |
| [BMP280 temperature/barometer](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf) | I2C |
| [BMP388 pressure sensor](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf) | I2C |
| [Buzzer](https://en.wikipedia.org/wiki/Buzzer#Piezoelectric) | GPIO |
| [DHTXX thermometer and humidity sensor](https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf) | GPIO |
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
| [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI |
@@ -81,32 +78,23 @@ The following 66 devices are supported.
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
| [ILI9341 TFT color display](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) | SPI |
| [INA260 Volt/Amp/Power meter](https://www.ti.com/lit/ds/symlink/ina260.pdf) | I2C |
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
| [L293x motor driver](https://www.ti.com/lit/ds/symlink/l293d.pdf) | GPIO/PWM |
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
| [LIS2MDL magnetometer](https://www.st.com/resource/en/datasheet/lis2mdl.pdf) | I2C |
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.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 |
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
| [Semihosting](https://wiki.segger.com/Semihosting) | Debug |
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
| [SSD1351 OLED display](https://download.mikroe.com/documents/datasheets/ssd1351-revision-1.3.pdf) | SPI |
@@ -114,7 +102,6 @@ The following 66 devices are supported.
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
| [Stepper motor "Easystepper" controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
| [TM1637 7-segment LED display](https://www.mcielectronics.cl/website_MCI/static/documents/Datasheet_TM1637.pdf) | I2C |
| [TMP102 I2C Temperature Sensor](https://download.mikroe.com/documents/datasheets/tmp102-data-sheet.pdf) | I2C |
| [VEML6070 UV light sensor](https://www.vishay.com/docs/84277/veml6070.pdf) | I2C |
| [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C |
+2 -2
View File
@@ -18,13 +18,13 @@ func TestWhoAmI(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice(c, Address)
copy(fake.Registers[:], defaultRegisters())
fake.SetupRegisters(defaultRegisters())
bus.AddDevice(fake)
dev := New(bus)
c.Assert(dev.Connected(), qt.Equals, true)
fake.Registers[RegID] = 0x99
fake.SetupRegister(RegID, 0x99)
c.Assert(dev.Connected(), qt.Equals, false)
}
-108
View File
@@ -1,108 +0,0 @@
package aht20
import (
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to an AHT20 device.
type Device struct {
bus drivers.I2C
Address uint16
humidity uint32
temp uint32
}
// New creates a new AHT20 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
}
}
// Configure the device
func (d *Device) Configure() {
// Check initialization state
status := d.Status()
if status&0x08 == 1 {
// Device is initialized
return
}
// Force initialization
d.bus.Tx(d.Address, []byte{CMD_INITIALIZE, 0x08, 0x00}, nil)
time.Sleep(10 * time.Millisecond)
}
// Reset the device
func (d *Device) Reset() {
d.bus.Tx(d.Address, []byte{CMD_SOFTRESET}, nil)
}
// Status of the device
func (d *Device) Status() byte {
data := []byte{0}
d.bus.Tx(d.Address, []byte{CMD_STATUS}, data)
return data[0]
}
// Read the temperature and humidity
//
// The actual temperature and humidity are stored
// and can be accessed using `Temp` and `Humidity`.
func (d *Device) Read() error {
d.bus.Tx(d.Address, []byte{CMD_TRIGGER, 0x33, 0x00}, nil)
data := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
for retry := 0; retry < 3; retry++ {
time.Sleep(80 * time.Millisecond)
err := d.bus.Tx(d.Address, nil, data)
if err != nil {
return err
}
// If measurement complete, store values
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
return nil
}
}
return ErrTimeout
}
func (d *Device) RawHumidity() uint32 {
return d.humidity
}
func (d *Device) RawTemp() uint32 {
return d.temp
}
func (d *Device) RelHumidity() float32 {
return (float32(d.humidity) * 100) / 0x100000
}
func (d *Device) DeciRelHumidity() int32 {
return (int32(d.humidity) * 1000) / 0x100000
}
// Temperature in degrees celsius
func (d *Device) Celsius() float32 {
return (float32(d.temp*200.0) / 0x100000) - 50
}
// Temperature in mutiples of one tenth of a degree celsius
//
// Using this method avoids floating point calculations.
func (d *Device) DeciCelsius() int32 {
return ((int32(d.temp) * 2000) / 0x100000) - 500
}
-74
View File
@@ -1,74 +0,0 @@
package aht20
import (
"testing"
qt "github.com/frankban/quicktest"
"tinygo.org/x/drivers/tester"
)
func TestDefaultI2CAddress(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
c.Assert(uint8(dev.Address), qt.Equals, uint8(Address))
}
func TestInitialization(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fdev := tester.NewI2CDeviceCmd(c, Address)
fdev.Commands = defaultCommands()
bus.AddDevice(fdev)
// Set status to uninitialized to force initialization
fdev.Commands[CMD_STATUS].Response[0] = 0x0C
dev := New(bus)
dev.Configure()
// Check initialization command invoked
c.Assert(fdev.Commands[CMD_INITIALIZE].Invocations > 0, qt.Equals, true)
}
func TestRead(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fdev := tester.NewI2CDeviceCmd(c, Address)
fdev.Commands = defaultCommands()
bus.AddDevice(fdev)
dev := New(bus)
dev.Read()
// Should be 25deg (250 decidegrees)
c.Assert(dev.DeciCelsius(), qt.Equals, int32(250))
// Should be 36.3% (363 decipercent)
c.Assert(dev.DeciRelHumidity(), qt.Equals, int32(363))
}
func defaultCommands() map[uint8]*tester.Cmd {
return map[uint8]*tester.Cmd{
CMD_INITIALIZE: {
Command: []byte{0xBE},
Mask: []byte{0xFF},
Response: []byte{},
},
CMD_TRIGGER: {
Command: []byte{0xAC, 0x33, 0x00},
Mask: []byte{0xFF, 0xFF, 0xFF},
Response: []byte{0x1C, 0x5D, 0x10, 0x66, 0x01, 0xD2, 0x93},
},
CMD_SOFTRESET: {
Command: []byte{0xBA},
Mask: []byte{0xFF},
Response: []byte{},
},
CMD_STATUS: {
Command: []byte{0x71},
Mask: []byte{0xFF},
Response: []byte{0x1C},
},
}
}
-20
View File
@@ -1,20 +0,0 @@
package aht20
import "errors"
const (
Address = 0x38
CMD_INITIALIZE = 0xBE
CMD_STATUS = 0x71
CMD_TRIGGER = 0xAC
CMD_SOFTRESET = 0xBA
STATUS_BUSY = 0x80
STATUS_CALIBRATED = 0x08
)
var (
ErrBusy = errors.New("device busy")
ErrTimeout = errors.New("timeout")
)
+17 -19
View File
@@ -27,46 +27,44 @@ var startFrame = []byte{0x00, 0x00, 0x00, 0x00}
type Device struct {
bus drivers.SPI
Order int
buf [4]byte
}
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI) *Device {
return &Device{bus: b, Order: BGR}
func New(b drivers.SPI) Device {
return Device{bus: b, Order: BGR}
}
// NewSoftwareSPI returns a new APA102 driver that will use a software based
// implementation of the SPI protocol.
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) Device {
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
}
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
// The A value (Alpha channel) is used for brightness, set to 0xff (255) for maximum.
func (d *Device) WriteColors(cs []color.RGBA) (n int, err error) {
func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
d.startFrame()
// write data
for _, c := range cs {
// brightness is scaled to 5 bit value
d.buf[0] = 0xe0 | (c.A >> 3)
d.bus.Transfer(0xe0 | (c.A >> 3))
// set the colors
switch d.Order {
case BRG:
d.buf[1] = c.B
d.buf[2] = c.R
d.buf[3] = c.G
d.bus.Transfer(c.B)
d.bus.Transfer(c.R)
d.bus.Transfer(c.G)
case GRB:
d.buf[1] = c.G
d.buf[2] = c.R
d.buf[3] = c.B
d.bus.Transfer(c.G)
d.bus.Transfer(c.R)
d.bus.Transfer(c.B)
case BGR:
d.buf[1] = c.B
d.buf[2] = c.G
d.buf[3] = c.R
d.bus.Transfer(c.B)
d.bus.Transfer(c.G)
d.bus.Transfer(c.R)
}
d.bus.Tx(d.buf[:], nil)
}
d.endFrame(len(cs))
@@ -75,7 +73,7 @@ func (d *Device) WriteColors(cs []color.RGBA) (n int, err error) {
}
// Write the raw bytes using the APA102 protocol.
func (d *Device) Write(buf []byte) (n int, err error) {
func (d Device) Write(buf []byte) (n int, err error) {
d.startFrame()
d.bus.Tx(buf, nil)
d.endFrame(len(buf) / 4)
@@ -84,14 +82,14 @@ func (d *Device) Write(buf []byte) (n int, err error) {
}
// startFrame sends the start bytes for a strand of LEDs.
func (d *Device) startFrame() {
func (d Device) startFrame() {
d.bus.Tx(startFrame, nil)
}
// endFrame sends the end frame marker with one extra bit per LED so
// long strands of LEDs receive the necessary termination for updates.
// See https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/
func (d *Device) endFrame(count int) {
func (d Device) endFrame(count int) {
for i := 0; i < count/16; i++ {
d.bus.Transfer(0xff)
}
+5 -24
View File
@@ -13,8 +13,6 @@ type DeviceSPI struct {
// Chip select pin
CSB machine.Pin
buf [7]byte
// SPI bus (requires chip select to be usable).
Bus drivers.SPI
}
@@ -82,10 +80,7 @@ func (d *DeviceSPI) Reset() error {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
data := d.buf[:3]
data[0] = 0x80 | reg_TEMPERATURE_0
data[1] = 0
data[2] = 0
data := []byte{0x80 | reg_TEMPERATURE_0, 0, 0}
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -118,11 +113,7 @@ func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
data := d.buf[:7]
data[0] = 0x80 | reg_ACC_XL
for i := 1; i < len(data); i++ {
data[i] = 0
}
data := []byte{0x80 | reg_ACC_XL, 0, 0, 0, 0, 0, 0}
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -148,11 +139,7 @@ func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *DeviceSPI) ReadRotation() (x int32, y int32, z int32, err error) {
data := d.buf[:7]
data[0] = 0x80 | reg_GYR_XL
for i := 1; i < len(data); i++ {
data[i] = 0
}
data := []byte{0x80 | reg_GYR_XL, 0, 0, 0, 0, 0, 0}
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -198,9 +185,7 @@ func (d *DeviceSPI) readRegister(address uint8) uint8 {
// I don't know why but it appears necessary to sleep for a bit here.
time.Sleep(time.Millisecond)
data := d.buf[:2]
data[0] = 0x80 | address
data[1] = 0
data := []byte{0x80 | address, 0}
d.CSB.Low()
d.Bus.Tx(data, data)
d.CSB.High()
@@ -213,11 +198,7 @@ func (d *DeviceSPI) writeRegister(address, data uint8) {
// I don't know why but it appears necessary to sleep for a bit here.
time.Sleep(time.Millisecond)
buf := d.buf[:2]
buf[0] = address
buf[1] = data
d.CSB.Low()
d.Bus.Tx(buf, buf)
d.Bus.Tx([]byte{address, data}, []byte{0, 0})
d.CSB.High()
}
-249
View File
@@ -1,249 +0,0 @@
package bmp388
import (
"errors"
"tinygo.org/x/drivers"
)
var (
errConfigWrite = errors.New("bmp388: failed to configure sensor, check connection")
errConfig = errors.New("bmp388: there is a problem with the configuration, try reducing ODR")
errCaliRead = errors.New("bmp388: failed to read calibration coefficient register")
errSoftReset = errors.New("bmp388: failed to perform a soft reset")
errNotConnected = errors.New("bmp388: not connected")
)
type Oversampling byte
type Mode byte
type OutputDataRate byte
type FilterCoefficient byte
// Config contains settings for filtering, sampling, and modes of operation
type Config struct {
Pressure Oversampling
Temperature Oversampling
Mode Mode
ODR OutputDataRate
IIR FilterCoefficient
}
// Device wraps the I2C connection and configuration values for the BMP388
type Device struct {
bus drivers.I2C
Address uint8
cali calibrationCoefficients
Config Config
}
type calibrationCoefficients struct {
// Temperature compensation
t1 uint16
t2 uint16
t3 int8
// Pressure compensation
p1 int16
p2 int16
p3 int8
p4 int8
p5 uint16
p6 uint16
p7 int8
p8 int8
p9 int16
p10 int8
p11 int8
}
// New returns a bmp388 struct with the default I2C address. Configure must also be called after instanting
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
}
}
// Configure can enable settings on the BMP388 and reads the calibration coefficients
func (d *Device) Configure(config Config) (err error) {
d.Config = config
if d.Config == (Config{}) {
d.Config.Mode = Normal
}
// Turning on the pressure and temperature sensors and setting the measurement mode
err = d.writeRegister(RegPwrCtrl, PwrPress|PwrTemp|byte(d.Config.Mode))
// Configure the oversampling, output data rate, and iir filter coefficient settings
err = d.writeRegister(RegOSR, byte(d.Config.Pressure|d.Config.Temperature<<3))
err = d.writeRegister(RegODR, byte(d.Config.ODR))
err = d.writeRegister(RegIIR, byte(d.Config.IIR<<1))
if err != nil {
return errConfigWrite
}
// Check if there is a problem with the given configuration
if d.configurationError() {
return errConfig
}
// Reading the builtin calibration coefficients and parsing them per the datasheet. The compensation formula given
// in the datasheet is implemented in floating point
buffer, err := d.readRegister(RegCali, 21)
if err != nil {
return errCaliRead
}
d.cali.t1 = uint16(buffer[1])<<8 | uint16(buffer[0])
d.cali.t2 = uint16(buffer[3])<<8 | uint16(buffer[2])
d.cali.t3 = int8(buffer[4])
d.cali.p1 = int16(buffer[6])<<8 | int16(buffer[5])
d.cali.p2 = int16(buffer[8])<<8 | int16(buffer[7])
d.cali.p3 = int8(buffer[9])
d.cali.p4 = int8(buffer[10])
d.cali.p5 = uint16(buffer[12])<<8 | uint16(buffer[11])
d.cali.p6 = uint16(buffer[14])<<8 | uint16(buffer[13])
d.cali.p7 = int8(buffer[15])
d.cali.p8 = int8(buffer[16])
d.cali.p9 = int16(buffer[18])<<8 | int16(buffer[17])
d.cali.p10 = int8(buffer[19])
d.cali.p11 = int8(buffer[20])
return nil
}
// Read the temperature registers and compute a compensation value for the temperature and pressure compensation
// calculations. This is not the temperature itself.
func (d *Device) tlinCompensate() (int64, error) {
rawTemp, err := d.readSensorData(RegTemp)
if err != nil {
return 0, err
}
// pulled from C driver: https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
partialData1 := rawTemp - (256 * int64(d.cali.t1))
partialData2 := int64(d.cali.t2) * partialData1
partialData3 := (partialData1 * partialData1)
partialData4 := partialData3 * int64(d.cali.t3)
partialData5 := (partialData2 * 262144) + partialData4
return partialData5 / 4294967296, nil
}
// ReadTemperature returns the temperature in centicelsius, i.e 2426 / 100 = 24.26 C
func (d *Device) ReadTemperature() (int32, error) {
tlin, err := d.tlinCompensate()
if err != nil {
return 0, err
}
temp := (tlin * 25) / 16384
return int32(temp), nil
}
// ReadPressure returns the pressure in centipascals, i.e 10132520 / 100 = 101325.20 Pa
func (d *Device) ReadPressure() (int32, error) {
tlin, err := d.tlinCompensate()
if err != nil {
return 0, err
}
rawPress, err := d.readSensorData(RegPress)
if err != nil {
return 0, err
}
// code pulled from bmp388 C driver: https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
partialData1 := tlin * tlin
partialData2 := partialData1 / 64
partialData3 := (partialData2 * tlin) / 256
partialData4 := (int64(d.cali.p8) * partialData3) / 32
partialData5 := (int64(d.cali.p7) * partialData1) * 16
partialData6 := (int64(d.cali.p6) * tlin) * 4194304
offset := (int64(d.cali.p5) * 140737488355328) + partialData4 + partialData5 + partialData6
partialData2 = (int64(d.cali.p4) * partialData3) / 32
partialData4 = (int64(d.cali.p3) * partialData1) * 4
partialData5 = (int64(d.cali.p2) - 16384) * tlin * 2097152
sensitivity := ((int64(d.cali.p1) - 16384) * 70368744177664) + partialData2 + partialData4 + partialData5
partialData1 = (sensitivity / 16777216) * rawPress
partialData2 = int64(d.cali.p10) * tlin
partialData3 = partialData2 + (65536 * int64(d.cali.p9))
partialData4 = (partialData3 * rawPress) / 8192
// dividing by 10 followed by multiplying by 10
// To avoid overflow caused by (pressure * partial_data4)
partialData5 = (rawPress * (partialData4 / 10)) / 512
partialData5 = partialData5 * 10
partialData6 = (int64)(uint64(rawPress) * uint64(rawPress))
partialData2 = (int64(d.cali.p11) * partialData6) / 65536
partialData3 = (partialData2 * rawPress) / 128
partialData4 = (offset / 4) + partialData1 + partialData5 + partialData3
compPress := ((uint64(partialData4) * 25) / uint64(1099511627776))
return int32(compPress), nil
}
// SoftReset commands the BMP388 to reset of all user configuration settings
func (d *Device) SoftReset() error {
err := d.writeRegister(RegCmd, SoftReset)
if err != nil {
return errSoftReset
}
return nil
}
// Connected tries to reach the bmp388 and check its chip id register. Returns true if it was able to successfully
// communicate over i2c and returns the correct value
func (d *Device) Connected() bool {
data, err := d.readRegister(RegChipId, 1)
return err == nil && data[0] == ChipId // returns true if i2c comm was good and response equals 0x50
}
// SetMode changes the run mode of the sensor, NORMAL is the one to use for most cases. Use FORCED if you plan to take
// measurements infrequently and want to conserve power. SLEEP will of course put the sensor to sleep
func (d *Device) SetMode(mode Mode) error {
d.Config.Mode = mode
return d.writeRegister(RegPwrCtrl, PwrPress|PwrTemp|byte(d.Config.Mode))
}
func (d *Device) readSensorData(register byte) (data int64, err error) {
if !d.Connected() {
return 0, errNotConnected
}
// put the sensor back into forced mode to get a reading, the sensor goes back to sleep after taking one read in
// forced mode
if d.Config.Mode != Normal {
err = d.SetMode(Forced)
if err != nil {
return
}
}
bytes, err := d.readRegister(register, 3)
if err != nil {
return
}
data = int64(bytes[2])<<16 | int64(bytes[1])<<8 | int64(bytes[0])
return
}
// configurationError checks the register error for the configuration error bit. The bit is cleared on read by the bmp.
func (d *Device) configurationError() bool {
data, err := d.readRegister(RegErr, 1)
return err == nil && (data[0]&0x04) != 0
}
func (d *Device) readRegister(register byte, len int) (data []byte, err error) {
data = make([]byte, len)
err = d.bus.ReadRegister(d.Address, register, data)
return
}
func (d *Device) writeRegister(register byte, data byte) error {
return d.bus.WriteRegister(d.Address, register, []byte{data})
}
-84
View File
@@ -1,84 +0,0 @@
// Package bmp388 provides a driver for Bosch's BMP388 digital temperature & pressure sensor.
// The datasheet can be found here: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
package bmp388
const Address byte = 0x77 // default I2C address
const (
RegChipId byte = 0x00 // useful for checking the connection
RegCali byte = 0x31 // pressure & temperature compensation calibration coefficients
RegPress byte = 0x04 // start of pressure data registers
RegTemp byte = 0x07 // start of temperature data registers
RegPwrCtrl byte = 0x1B // measurement mode & pressure/temperature sensor power register
RegOSR byte = 0x1C // oversampling settings register
RegODR byte = 0x1D //
RegCmd byte = 0x7E // miscellaneous command register
RegStat byte = 0x03 // sensor status register
RegErr byte = 0x02 // error status register
RegIIR byte = 0x1F
)
const (
ChipId byte = 0x50 // correct response if reading from chip id register
PwrPress byte = 0x01 // power on pressure sensor
PwrTemp byte = 0x02 // power on temperature sensor
SoftReset byte = 0xB6 // command to reset all user configuration
DRDYPress byte = 0x20 // for checking if pressure data is ready
DRDYTemp byte = 0x40 // for checking if pressure data is ready
)
// The difference between forced and normal mode is the bmp388 goes to sleep after taking a measurement in forced mode.
// Set it to forced if you intend to take measurements sporadically and want to save power. The driver will handle
// waking the sensor up when the sensor is in forced mode.
const (
Normal Mode = 0x30
Forced Mode = 0x16
Sleep Mode = 0x00
)
// Increasing sampling rate increases precision but also the wait time for measurements. The datasheet has a table of
// suggested values for oversampling, output data rates, and iir filter coefficients by use case.
const (
Sampling1X Oversampling = iota
Sampling2X
Sampling4X
Sampling8X
Sampling16X
Sampling32X
)
// Output data rates in Hz. If increasing the sampling rates you need to decrease the output data rates, else the bmp388
// will freeze and Configure() will return a configuration error message. In that case keep decreasing the data rate
// until the bmp is happy
const (
Odr200 OutputDataRate = iota
Odr100
Odr50
Odr25
Odr12p5
Odr6p25
Odr3p1
Odr1p5
Odr0p78
Odr0p39
Odr0p2
Odr0p1
Odr0p05
Odr0p02
Odr0p01
Odr0p006
Odr0p003
Odr0p0015
)
// IIR filter coefficients, higher values means steadier measurements but slower reaction times
const (
Coeff0 FilterCoefficient = iota
Coeff1
Coeff3
Coeff7
Coeff15
Coeff31
Coeff63
Coeff127
)
-116
View File
@@ -1,116 +0,0 @@
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
package dht // import "tinygo.org/x/drivers/dht"
import (
"encoding/binary"
"machine"
"time"
)
// enum type for device type
type DeviceType uint8
// DeviceType specific parsing of information received from the sensor
func (d DeviceType) extractData(buf []byte) (temp int16, hum uint16) {
if d == DHT11 {
temp = int16(buf[2])
if buf[3]&0x80 > 0 {
temp = -1 - temp
}
temp *= 10
temp += int16(buf[3] & 0x0f)
hum = 10*uint16(buf[0]) + uint16(buf[1])
} else {
hum = binary.LittleEndian.Uint16(buf[0:2])
temp = int16(buf[3])<<8 + int16(buf[2]&0x7f)
if buf[2]&0x80 > 0 {
temp = -temp
}
}
return
}
// Celsius and Fahrenheit temperature scales
type TemperatureScale uint8
func (t TemperatureScale) convertToFloat(temp int16) float32 {
if t == C {
return float32(temp) / 10
} else {
// Fahrenheit
return float32(temp)*(9.0/50.) + 32.
}
}
// All functions return ErrorCode instance as error. This class can be used for more efficient error processing
type ErrorCode uint8
const (
startTimeout = time.Millisecond * 200
startingLow = time.Millisecond * 20
DHT11 DeviceType = iota
DHT22
C TemperatureScale = iota
F
ChecksumError ErrorCode = iota
NoSignalError
NoDataError
UpdateError
UninitializedDataError
)
// error interface implementation for ErrorCode
func (e ErrorCode) Error() string {
switch e {
case ChecksumError:
// DHT returns ChecksumError if all the data from the sensor was received, but the checksum does not match.
return "checksum mismatch"
case NoSignalError:
// DHT returns NoSignalError if there was no reply from the sensor. Check sensor connection or the correct pin
// sis chosen,
return "no signal"
case NoDataError:
// DHT returns NoDataError if the connection was successfully initialized, but not all 40 bits from
// the sensor is received
return "no data"
case UpdateError:
// DHT returns UpdateError if ReadMeasurements function is called before time specified in UpdatePolicy or
// less than 2 seconds after past measurement
return "cannot update now"
case UninitializedDataError:
// DHT returns UninitializedDataError if user attempts to access data before first measurement
return "no measurements done"
}
// should never be reached
return "unknown error"
}
// Update policy of the DHT device. UpdateTime cannot be shorter than 2 seconds. According to dht specification sensor
// will return undefined data if update requested less than 2 seconds before last usage
type UpdatePolicy struct {
UpdateTime time.Duration
UpdateAutomatically bool
}
var (
// timeout counter equal to number of ticks per 1 millisecond
timeout counter
)
func init() {
timeout = cyclesPerMillisecond()
}
func cyclesPerMillisecond() counter {
freq := machine.CPUFrequency()
freq /= 1000
return counter(freq)
}
-6
View File
@@ -1,6 +0,0 @@
// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407
package dht // import "tinygo.org/x/drivers/dht"
// This file provides a definition of the counter for boards with frequency higher than 2^8 ticks per millisecond (>64MHz)
type counter uint32
-6
View File
@@ -1,6 +0,0 @@
// +build arduino atmega1284p nrf52840 digispark nrf52 arduino_nano nrf51 atsamd21 fe310 arduino_nano33 circuitplay_express arduino_mega2560
package dht // import "tinygo.org/x/drivers/dht"
// This file provides a definition of the counter for boards with frequency lower than 2^8 ticks per millisecond (<64MHz)
type counter uint16
-218
View File
@@ -1,218 +0,0 @@
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
package dht // import "tinygo.org/x/drivers/dht"
import (
"machine"
"time"
)
// DummyDevice provides a basic interface for DHT devices.
type DummyDevice interface {
ReadMeasurements() error
Measurements() (temperature int16, humidity uint16, err error)
Temperature() (int16, error)
TemperatureFloat(scale TemperatureScale) (float32, error)
Humidity() (uint16, error)
HumidityFloat() (float32, error)
}
// Basic implementation of the DummyDevice
// This implementation takes measurements from sensor only with ReadMeasurements function
// and does not provide a protection from too frequent calls for measurements.
// Since taking measurements from the sensor is time consuming procedure and blocks interrupts,
// user can avoid any hidden calls to the sensor.
type device struct {
pin machine.Pin
measurements DeviceType
initialized bool
temperature int16
humidity uint16
}
// ReadMeasurements reads data from the sensor.
// According to documentation pin should be always, but the t *device restores pin to the state before call.
func (t *device) ReadMeasurements() error {
// initial waiting
state := powerUp(t.pin)
defer t.pin.Set(state)
err := t.read()
if err == nil {
t.initialized = true
}
return err
}
// Getter for temperature. Temperature method returns temperature as it is sent by device.
// The temperature is measured temperature in Celsius multiplied by 10.
// If no successful measurements for this device was performed, returns UninitializedDataError.
func (t *device) Temperature() (int16, error) {
if !t.initialized {
return 0, UninitializedDataError
}
return t.temperature, nil
}
// Getter for temperature. TemperatureFloat returns temperature in a given scale.
// If no successful measurements for this device was performed, returns UninitializedDataError.
func (t *device) TemperatureFloat(scale TemperatureScale) (float32, error) {
if !t.initialized {
return 0, UninitializedDataError
}
return scale.convertToFloat(t.temperature), nil
}
// Getter for humidity. Humidity returns humidity as it is sent by device.
// The humidity is measured in percentages multiplied by 10.
// If no successful measurements for this device was performed, returns UninitializedDataError.
func (t *device) Humidity() (uint16, error) {
if !t.initialized {
return 0, UninitializedDataError
}
return t.humidity, nil
}
// Getter for humidity. HumidityFloat returns humidity in percentages.
// If no successful measurements for this device was performed, returns UninitializedDataError.
func (t *device) HumidityFloat() (float32, error) {
if !t.initialized {
return 0, UninitializedDataError
}
return float32(t.humidity) / 10., nil
}
// Perform initialization of the communication protocol.
// Device lowers the voltage on pin for startingLow=20ms and starts listening for response
// Section 5.2 in [1]
func initiateCommunication(p machine.Pin) {
// Send low signal to the device
p.Configure(machine.PinConfig{Mode: machine.PinOutput})
p.Low()
time.Sleep(startingLow)
// Set pin to high and wait for reply
p.High()
p.Configure(machine.PinConfig{Mode: machine.PinInput})
}
// Measurements returns both measurements: temperature and humidity as they sent by the device.
// If no successful measurements for this device was performed, returns UninitializedDataError.
func (t *device) Measurements() (temperature int16, humidity uint16, err error) {
if !t.initialized {
return 0, 0, UninitializedDataError
}
temperature = t.temperature
humidity = t.humidity
err = nil
return
}
// Main routine that performs communication with the sensor
func (t *device) read() error {
// initialize loop variables
// buffer for the data sent by the sensor. Sensor sends 40 bits = 5 bytes
bufferData := [5]byte{}
buf := bufferData[:]
// We perform measurements of the signal from the sensor by counting low and high cycles.
// The bit is determined by the relative length of the high signal to low signal.
// For 1, high signal will be longer than low, for 0---low is longer.
// See section 5.3 [1]
signalsData := [80]counter{}
signals := signalsData[:]
// Start communication protocol with sensor
initiateCommunication(t.pin)
// Wait for sensor's response and abort if sensor does not reply
err := waitForDataTransmission(t.pin)
if err != nil {
return err
}
// count low and high cycles for sensor's reply
receiveSignals(t.pin, signals)
// process received signals and store the result in the buffer. Abort if data transmission was interrupted and not
// all 40 bits were received
err = t.extractData(signals[:], buf)
if err != nil {
return err
}
// Compute checksum and compare it to the one in data. Abort if checksum is incorrect
if !isValid(buf[:]) {
return ChecksumError
}
// Extract temperature and humidity data from buffer
t.temperature, t.humidity = t.measurements.extractData(buf)
return nil
}
// receiveSignals counts number of low and high cycles. The execution is time critical, so the function disables
// interrupts
func receiveSignals(pin machine.Pin, result []counter) {
i := uint8(0)
machine.UART1.Interrupt.Disable()
defer machine.UART1.Interrupt.Enable()
for ; i < 40; i++ {
result[i*2] = expectChange(pin, false)
result[i*2+1] = expectChange(pin, true)
}
}
// extractData process signal counters and transforms them into bits.
// if any of the bits were not received (timed-out), returns NoDataError
func (t *device) extractData(signals []counter, buf []uint8) error {
for i := uint8(0); i < 40; i++ {
lowCycle := signals[i*2]
highCycle := signals[i*2+1]
if lowCycle == timeout || highCycle == timeout {
return NoDataError
}
byteN := i >> 3
buf[byteN] <<= 1
if highCycle > lowCycle {
buf[byteN] |= 1
}
}
return nil
}
// waitForDataTransmission waits for reply from the sensor.
// If no reply received, returns NoSignalError.
// For more details, see section 5.2 in [1]
func waitForDataTransmission(p machine.Pin) error {
// wait for thermometer to pull down
if expectChange(p, true) == timeout {
return NoSignalError
}
//wait for thermometer to pull up
if expectChange(p, false) == timeout {
return NoSignalError
}
// wait for thermometer to pull down and start sending the data
if expectChange(p, true) == timeout {
return NoSignalError
}
return nil
}
// Constructor function for a DummyDevice implementation.
// This device provides full control to the user.
// It does not do any hidden measurements calls and does not check
// for 2 seconds delay between measurements.
func NewDummyDevice(pin machine.Pin, deviceType DeviceType) DummyDevice {
pin.High()
return &device{
pin: pin,
measurements: deviceType,
initialized: false,
temperature: 0,
humidity: 0,
}
}
-154
View File
@@ -1,154 +0,0 @@
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
package dht // import "tinygo.org/x/drivers/dht"
import (
"machine"
"time"
)
// Device interface provides main functionality of the DHTXX sensors.
type Device interface {
DummyDevice
Configure(policy UpdatePolicy)
}
// managedDevice struct provides time control and optional automatic data retrieval from the sensor.
// It delegates all the functionality to device
type managedDevice struct {
t device
lastUpdate time.Time
policy UpdatePolicy
}
// Measurements returns both measurements: temperature and humidity as they sent by the device.
// Depending on the UpdatePolicy of the device may update cached measurements.
func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) {
err = m.checkForUpdateOnDataRequest()
if err != nil {
return 0, 0, err
}
return m.t.Measurements()
}
// Getter for temperature. Temperature method returns temperature as it is sent by device.
// The temperature is measured temperature in Celsius multiplied by 10.
// Depending on the UpdatePolicy of the device may update cached measurements.
func (m *managedDevice) Temperature() (temp int16, err error) {
err = m.checkForUpdateOnDataRequest()
if err != nil {
return 0, err
}
temp, err = m.t.Temperature()
return
}
func (m *managedDevice) checkForUpdateOnDataRequest() (err error) {
// update if necessary
if m.policy.UpdateAutomatically {
err = m.ReadMeasurements()
}
// ignore error if the data was updated recently
// interface comparison does not work in tinygo. Therefore need to cast to explicit type
if code, ok := err.(ErrorCode); ok && code == UpdateError {
err = nil
}
// add error if the data is not initialized
if !m.t.initialized {
err = UninitializedDataError
}
return err
}
// Getter for temperature. TemperatureFloat returns temperature in a given scale.
// Depending on the UpdatePolicy of the device may update cached measurements.
func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) {
err := m.checkForUpdateOnDataRequest()
if err != nil {
return 0, err
}
return m.t.TemperatureFloat(scale)
}
// Getter for humidity. Humidity returns humidity as it is sent by device.
// The humidity is measured in percentages multiplied by 10.
// Depending on the UpdatePolicy of the device may update cached measurements.
func (m *managedDevice) Humidity() (hum uint16, err error) {
err = m.checkForUpdateOnDataRequest()
if err != nil {
return 0, err
}
return m.t.Humidity()
}
// Getter for humidity. HumidityFloat returns humidity in percentages.
// Depending on the UpdatePolicy of the device may update cached measurements.
func (m *managedDevice) HumidityFloat() (float32, error) {
err := m.checkForUpdateOnDataRequest()
if err != nil {
return 0, err
}
return m.t.HumidityFloat()
}
// ReadMeasurements reads data from the sensor.
// The function will return UpdateError if it is called more frequently than specified in UpdatePolicy
func (m *managedDevice) ReadMeasurements() (err error) {
timestamp := time.Now()
if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime {
err = m.t.ReadMeasurements()
} else {
err = UpdateError
}
if err == nil {
m.lastUpdate = timestamp
}
return
}
// Configure configures UpdatePolicy for Device.
// Configure checks for policy.UpdateTime and prevent from updating more frequently than specified in [1][2]
// to prevent undefined behaviour of the sensor.
func (m *managedDevice) Configure(policy UpdatePolicy) {
if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 {
policy.UpdateTime = time.Second * 2
}
m.policy = policy
}
// Constructor of the Device implementation.
// This implementation updates data every 2 seconds during data access.
func New(pin machine.Pin, deviceType DeviceType) Device {
pin.High()
return &managedDevice{
t: device{
pin: pin,
measurements: deviceType,
initialized: false,
},
lastUpdate: time.Time{},
policy: UpdatePolicy{
UpdateTime: time.Second * 2,
UpdateAutomatically: true,
},
}
}
// Constructor of the Device implementation with given UpdatePolicy
func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device {
pin.High()
result := &managedDevice{
t: device{
pin: pin,
measurements: deviceType,
initialized: false,
},
lastUpdate: time.Time{},
}
result.Configure(updatePolicy)
return result
}
-34
View File
@@ -1,34 +0,0 @@
package dht // import "tinygo.org/x/drivers/dht"
import (
"machine"
"time"
)
// Check if the pin is disabled
func powerUp(p machine.Pin) bool {
state := p.Get()
if !state {
p.High()
time.Sleep(startTimeout)
}
return state
}
func expectChange(p machine.Pin, oldState bool) counter {
cnt := counter(0)
for ; p.Get() == oldState && cnt != timeout; cnt++ {
}
return cnt
}
func checksum(buf []uint8) uint8 {
return buf[4]
}
func computeChecksum(buf []uint8) uint8 {
return buf[0] + buf[1] + buf[2] + buf[3]
}
func isValid(buf []uint8) bool {
return checksum(buf) == computeChecksum(buf)
}
+3 -3
View File
@@ -20,17 +20,17 @@ package espat // import "tinygo.org/x/drivers/espat"
import (
"errors"
"machine"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/net"
)
// Device wraps UART connection to the ESP8266/ESP32.
type Device struct {
bus drivers.UART
bus machine.UART
// command responses that come back from the ESP8266/ESP32
response []byte
@@ -43,7 +43,7 @@ type Device struct {
var ActiveDevice *Device
// New returns a new espat driver. Pass in a fully configured UART bus.
func New(b drivers.UART) *Device {
func New(b machine.UART) *Device {
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
}
+1 -1
View File
@@ -9,7 +9,7 @@ import (
)
var (
i2c = machine.I2C0
i2c = &machine.I2C0
sensor = adt7410.New(i2c)
)
-55
View File
@@ -1,55 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/aht20"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
dev := aht20.New(machine.I2C0)
dev.Configure()
dev.Reset()
for {
time.Sleep(500 * time.Millisecond)
err := dev.Read()
if err != nil {
println("Error", err)
continue
}
println("temp ", fmtD(dev.DeciCelsius(), 3, 1), "C")
println("humidity", fmtD(dev.DeciRelHumidity(), 3, 1), "%")
}
}
func fmtD(val int32, i int, f int) string {
result := make([]byte, i+f+1)
neg := false
if val < 0 {
val = -val
neg = true
}
for p := len(result) - 1; p >= 0; p-- {
result[p] = byte(int32('0') + (val % 10))
val = val / 10
if p == i+1 && p > 0 {
p--
result[p] = '.'
}
}
if neg {
result[0] = '-'
}
return string(result)
}
+8 -15
View File
@@ -13,9 +13,9 @@ import (
)
var (
apa *apa102.Device
apa apa102.Device
pwm = machine.TCC0
led = machine.PWM{machine.LED}
leds = make([]color.RGBA, 1)
wheel = &Wheel{Brightness: 0x10}
)
@@ -27,19 +27,12 @@ func init() {
apa = apa102.NewSoftwareSPI(machine.PA00, machine.PA01, 1)
// Configure the regular on-board LED for PWM fading
err := pwm.Configure(machine.PWMConfig{})
if err != nil {
println("failed to configure PWM")
return
}
machine.InitPWM()
led.Configure()
}
func main() {
channelLED, err := pwm.Channel(machine.LED)
if err != nil {
println("failed to configure LED PWM channel")
return
}
// We'll fade the on-board LED in a goroutine to show/ensure that the APA102
// works fine with the scheduler enabled. Comment this out to test this code
@@ -50,11 +43,11 @@ func main() {
brightening = !brightening
continue
}
var brightness uint32 = uint32(i)
var brightness uint16 = uint16(i) << 8
if !brightening {
brightness = 256 - brightness
brightness = 0xFFFF - brightness
}
pwm.Set(channelLED, pwm.Top()*brightness/256)
led.Set(brightness)
time.Sleep(5 * time.Millisecond)
}
}()
-53
View File
@@ -1,53 +0,0 @@
package main
import (
"machine"
"strconv"
"time"
"tinygo.org/x/drivers/bmp388"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
sensor := bmp388.New(machine.I2C0)
if !sensor.Connected() {
println("Uh oh, BMP388 not detected")
return
}
// The accuracy of the sensor can be increased, at the cost of a slower output rate. Table 9 in Section 3.5 of the
// datasheet has recommended settings for common use cases. If increasing the sampling rate, the output data rate
// (ODR) will likely have to be decreased. Configure() will return an error if there's a problem with the
// configuration settings - keep decreasing the ODR and cycling the power to the sensor until it is happy.
err := sensor.Configure(bmp388.Config{
Pressure: bmp388.Sampling8X,
Temperature: bmp388.Sampling2X,
ODR: bmp388.Odr25,
IIR: bmp388.Coeff0,
Mode: bmp388.Normal,
})
// This is also fine
// err := sensor.Configure(bmp388.BMP388Config{})
if err != nil {
println(err)
}
for {
temp, err := sensor.ReadTemperature() // returns the temperature in centicelsius
press, err := sensor.ReadPressure() // returns the pressure in centipascals
if err != nil {
println(err)
} else {
println("Temperature: " + strconv.FormatInt(int64(temp), 10) + " cC")
println("Pressure: " + strconv.FormatInt(int64(press), 10) + " cPa\n")
}
time.Sleep(time.Second)
}
}
-23
View File
@@ -1,23 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/dht"
)
func main() {
pin := machine.D6
dhtSensor := dht.New(pin, dht.DHT11)
for {
temp, hum, err := dhtSensor.Measurements()
if err != nil {
fmt.Printf("Temperature: %02d.%d°C, Humidity: %02d.%d%%\n", temp/10, temp%10, hum/10, hum%10)
} else {
fmt.Printf("Could not take measurements from the sensor: %s\n", err.Error())
}
// Measurements cannot be updated only 2 seconds. More frequent calls will return the same value
time.Sleep(time.Second * 2)
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
console = machine.UART0
adaptor *espat.Device
)
+1 -1
View File
@@ -36,7 +36,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
console = machine.UART0
adaptor *espat.Device
topic = "tinygo"
+1 -1
View File
@@ -37,7 +37,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.Serial
console = machine.UART0
adaptor *espat.Device
cl mqtt.Client
+1 -1
View File
@@ -20,7 +20,7 @@ var (
input [consoleBufLen]byte
store [storageBufLen]byte
console = machine.Serial
console = machine.UART0
dev *flash.Device
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS I2C Example")
machine.I2C0.Configure(machine.I2CConfig{})
ublox := gps.NewI2C(machine.I2C0)
ublox := gps.NewI2C(&machine.I2C0)
parser := gps.NewParser()
var fix gps.Fix
for {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS UART Example")
machine.UART1.Configure(machine.UARTConfig{BaudRate: 9600})
ublox := gps.NewUART(machine.UART1)
ublox := gps.NewUART(&machine.UART1)
parser := gps.NewParser()
var fix gps.Fix
for {
+1 -1
View File
@@ -1,4 +1,4 @@
package main
package hcsr04
import (
"machine"
File diff suppressed because it is too large Load Diff
+69 -128
View File
@@ -10,25 +10,6 @@ import (
"tinygo.org/x/drivers/ili9341"
)
const (
BALLWIDTH = 136
BALLHEIGHT = 100
)
const (
SCREENHEIGHT = 240
SCREENWIDTH = 320
)
const (
invBGCOLOR = 0x75AD
invGRIDCOLOR = 0x15A8
invBGSHADOW = 0x8552
invGRIDSHADOW = 0x0C60
invRED = 0x00F8
invWHITE = 0xFFFF
)
const (
BGCOLOR = 0xAD75
GRIDCOLOR = 0xA815
@@ -44,12 +25,7 @@ const (
)
var (
dbg5 = machine.D5
dbg6 = machine.D6
)
var (
frameBuffer = [2][(BALLHEIGHT + 8) * (BALLWIDTH + 8)]uint16{}
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8)]uint16{}
startTime int64
frame int64
@@ -95,18 +71,14 @@ func main() {
balloldx = ballx
balloldy = bally // Prior ball position
var bufIdx int8 = 0
for {
dbg5.High()
bufIdx = 1 - bufIdx
balloldx = ballx // Save prior position
balloldy = bally
ballx += ballvx // Update position
bally += ballvy
ballvy += 0.06 // Update Y velocity
if (ballx <= 15) || (ballx >= SCREENWIDTH-BALLWIDTH) {
if (ballx <= 15) || (ballx >= graphics.SCREENWIDTH-graphics.BALLWIDTH) {
ballvx *= -1 // Left/right bounce
}
if bally >= YBOTTOM { // Hit ground?
@@ -128,13 +100,13 @@ func main() {
if int16(balloldy) < miny {
miny = int16(balloldy)
}
maxx = int16(ballx + BALLWIDTH - 1)
if int16(balloldx+BALLWIDTH-1) > maxx {
maxx = int16(balloldx + BALLWIDTH - 1)
maxx = int16(ballx + graphics.BALLWIDTH - 1)
if int16(balloldx+graphics.BALLWIDTH-1) > maxx {
maxx = int16(balloldx + graphics.BALLWIDTH - 1)
}
maxy = int16(bally + BALLHEIGHT - 1)
if int16(balloldy+BALLHEIGHT-1) > maxy {
maxy = int16(balloldy + BALLHEIGHT - 1)
maxy = int16(bally + graphics.BALLHEIGHT - 1)
if int16(balloldy+graphics.BALLHEIGHT-1) > maxy {
maxy = int16(balloldy + graphics.BALLHEIGHT - 1)
}
width = maxx - minx + 1
@@ -148,13 +120,13 @@ func main() {
ballframe -= 14
}
//// Set 7 palette entries to white, 7 to red, based on frame number.
//// This makes the ball spin
// Set 7 palette entries to white, 7 to red, based on frame number.
// This makes the ball spin
for i := 0; i < 14; i++ {
if (int(ballframe)+i)%14 < 7 {
palette[i+2] = invWHITE
palette[i+2] = WHITE
} else {
palette[i+2] = invRED
palette[i+2] = RED
} // Palette entries 0 and 1 aren't used (clear and shadow, respectively)
}
@@ -164,100 +136,61 @@ func main() {
by := miny - int16(bally) // Y relative to ball bitmap (can be negative)
bgx := minx // X relative to background bitmap (>= 0)
bgy := miny // Y relative to background bitmap (>= 0)
//var bufIdx int8 = 0
var bx1, bgx1 int16 // Loop counters and working vars
var p uint8 // 'packed' value of 2 ball pixels
var bufIdx int8 = 0
//tft.setAddrWindow(minx, miny, width, height)
//dbg5.Low()
dbg6.High()
//fmt.Printf("%d < %d < %d < %d\r\n", by, 0, BALLHEIGHT, height)
y := 0
if by < 0 {
max := -1 * int(by)
for y = 0; y < max; y++ { // For each row...
var bgidxBase = int(bgy)*(SCREENWIDTH) + int(bgx)
var yBase = y * int(width)
for x := 0; x < int(width); x++ {
frameBuffer[bufIdx][yBase+x] = graphics.Background[bgidxBase+x]
}
bgy++
}
}
y2 := y
max := 0
if bx < 0 {
max = -1 * int(bx)
bgy2 := bgy
for y = y2; y < y2+int(BALLHEIGHT); y++ { // For each row...
var bgidxBase = int(bgy2)*(SCREENWIDTH) + int(bgx)
var yBase = y * int(width)
//fmt.Printf("- %d %d %d %d %d %d\r\n", bgy, y, bgx, max, yBase, bgidxBase)
for x := 0; x < int(max); x++ {
//fmt.Printf(" %d %d\r\n", yBase+x, bgidxBase+x)
frameBuffer[bufIdx][yBase+x] = graphics.Background[bgidxBase+x]
}
bgy2++
}
//fmt.Printf("(%d, %d) - (%d, %d)\r\n", bx, 0, -1, BALLHEIGHT-1)
}
{
bgy2 := bgy
//fmt.Printf("(%d, %d) - (%d, %d)\r\n", 0, 0, BALLWIDTH-1, BALLHEIGHT-1)
for y = y2; y < y2+int(BALLHEIGHT); y++ { // For each row...
var bgidxBase = int(bgy2)*(SCREENWIDTH) + int(bgx)
var byBase = (y - y2) * BALLWIDTH
var yBase = y * int(width)
for x := max; x < int(BALLWIDTH)+max; x++ {
//fmt.Printf("%d %d %d %d\r\n", byBase, x, bgidxBase, yBase)
//time.Sleep(1 * time.Millisecond)
for y := 0; y < int(height); y++ { // For each row...
//destPtr = &renderbuf[bufIdx][0];
bx1 = bx // Need to keep the original bx and bgx values,
bgx1 = bgx // so copies of them are made here (and changed in loop below)
for x := 0; x < int(width); x++ {
var bgidx = int(bgy)*(graphics.SCREENWIDTH/8) + int(bgx1/8)
if (bx1 >= 0) && (bx1 < graphics.BALLWIDTH) && // Is current pixel row/column
(by >= 0) && (by < graphics.BALLHEIGHT) { // inside the ball bitmap area?
// Yes, do ball compositing math...
c = uint16(graphics.Ball[int(byBase)+x-max]) // Get packed value (2 pixels)
p = graphics.Ball[int(by*(graphics.BALLWIDTH/2))+int(bx1/2)] // Get packed value (2 pixels)
if (bx1 & 1) != 0 {
c = uint16(p & 0xF)
} else {
c = uint16(p >> 4)
} // Unpack high or low nybble
if c == 0 { // Outside ball - just draw grid
c = graphics.Background[bgidxBase+x]
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
c = GRIDCOLOR
} else {
c = BGCOLOR
}
} else if c > 1 { // In ball area...
c = palette[c]
} else { // In shadow area...
c = graphics.BackgroundShadow[bgidxBase+x]
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
c = GRIDSHADOW
} else {
c = BGSHADOW
}
}
} else { // Outside ball bitmap, just draw background bitmap...
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
c = GRIDCOLOR
} else {
c = BGCOLOR
}
frameBuffer[bufIdx][yBase+x] = c
}
bgy2++
frameBuffer[y*int(width)+x] = c
bx1++ // Increment bitmap position counters (X axis)
bgx1++
}
//tft.dmaWait(); // Wait for prior line to complete
//tft.writePixels(&renderbuf[bufIdx][0], width, false); // Non-blocking write
bufIdx = 1 - bufIdx
by++ // Increment bitmap position counters (Y axis)
bgy++
}
{
bgy2 := bgy
for y = y2; y < y2+int(BALLHEIGHT); y++ { // For each row...
var bgidxBase = int(bgy2)*(SCREENWIDTH) + int(bgx)
var yBase = y * int(width)
//fmt.Printf("+ %d %d %d %d %d\r\n", bgy, y, bgx, yBase, bgidxBase)
for x := int(BALLWIDTH) + max; x < int(width); x++ {
frameBuffer[bufIdx][yBase+x] = graphics.Background[bgidxBase+x]
}
bgy2++
}
}
y = y2 + int(BALLHEIGHT)
bgy += BALLHEIGHT
{
for ; y < int(height); y++ { // For each row...
//destPtr = &renderbuf[bufIdx][0];
var bgidxBase = int(bgy)*(SCREENWIDTH) + int(bgx)
var yBase = y * int(width)
for x := 0; x < int(width); x++ {
frameBuffer[bufIdx][yBase+x] = graphics.Background[bgidxBase+x]
}
bgy++
}
}
dbg6.Low()
display.DrawRGBBitmap(minx, miny, frameBuffer[bufIdx][:width*height], width, height)
//time.Sleep(10 * time.Millisecond)
display.DrawRGBBitmap(minx, miny, frameBuffer[:width*height], width, height)
// Show approximate frame rate
frame++
@@ -272,13 +205,21 @@ func main() {
func DrawBackground() {
w, h := display.Size()
var bufIdx int8 = 0
for j := 0; j < int(h); j++ {
bufIdx = 1 - bufIdx
for k := 0; k < int(w); k++ {
frameBuffer[bufIdx][k] = graphics.Background[j*int(w)+k]
byteWidth := (w + 7) / 8 // Bitmap scanline pad = whole byte
var b uint8
for j := int16(0); j < h; j++ {
for k := int16(0); k < w; k++ {
if k&7 > 0 {
b <<= 1
} else {
b = graphics.Background[j*byteWidth+k/8]
}
if b&0x80 == 0 {
frameBuffer[k] = BGCOLOR
} else {
frameBuffer[k] = GRIDCOLOR
}
}
display.DrawRGBBitmap(0, int16(j), frameBuffer[bufIdx][0:w], w, 1)
time.Sleep(1 * time.Millisecond)
display.DrawRGBBitmap(0, j, frameBuffer[0:w], w, 1)
}
}
-63
View File
@@ -1,63 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/ina260"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
dev := ina260.New(machine.I2C0)
dev.Configure(ina260.Config{
AverageMode: ina260.AVGMODE_16,
VoltConvTime: ina260.CONVTIME_140USEC,
CurrentConvTime: ina260.CONVTIME_140USEC,
Mode: ina260.MODE_CONTINUOUS | ina260.MODE_VOLTAGE | ina260.MODE_CURRENT,
})
if dev.Connected() {
println("INA260 detected")
} else {
println("INA260 NOT detected")
return
}
for {
microvolts := dev.Voltage()
microamps := dev.Current()
microwatts := dev.Power()
println(fmtD(microvolts, 4, 3), "mV,", fmtD(microamps, 4, 3), "mA,", fmtD(microwatts, 4, 3), "mW")
time.Sleep(10 * time.Millisecond)
}
}
func fmtD(val int32, i int, f int) string {
result := make([]byte, i+f+1)
neg := false
if val < 0 {
val = -val
neg = true
}
for p := len(result) - 1; p >= 0; p-- {
result[p] = byte(int32('0') + (val % 10))
val = val / 10
if p == i+1 && p > 0 {
p--
result[p] = '.'
}
}
if neg {
result[0] = '-'
}
return string(result)
}
-38
View File
@@ -1,38 +0,0 @@
package main
import (
"machine"
"tinygo.org/x/drivers/keypad4x4"
)
func main() {
mapping := map[uint8]string{
1: "1",
2: "2",
3: "3",
4: "A",
5: "4",
6: "5",
7: "6",
8: "B",
9: "7",
10: "8",
11: "9",
12: "C",
13: "*",
14: "0",
15: "#",
16: "D",
}
keypadDevice := keypad4x4.NewDevice(machine.D2, machine.D3, machine.D4, machine.D5, machine.D6, machine.D7, machine.D8, machine.D9)
keypadDevice.Configure()
for {
key := keypadDevice.GetKey()
if key != keypad4x4.NoKeyPressed {
println("Button: ", mapping[key])
}
}
}
+6 -18
View File
@@ -8,31 +8,19 @@ import (
)
const (
maxSpeed = 100
maxSpeed = 30000
)
func main() {
err := machine.TCC0.Configure(machine.PWMConfig{
Period: 16384e3, // 16.384ms
})
if err != nil {
println(err.Error())
return
}
machine.InitPWM()
spc, err := machine.TCC0.Channel(machine.D12)
if err != nil {
println(err.Error())
return
}
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, spc, machine.TCC0)
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, machine.PWM{machine.D12})
wheel.Configure()
for i := 0; i <= 10; i++ {
println("Forward")
var i uint32
for i = 0; i < maxSpeed; i += 10 {
var i uint16
for i = 0; i < maxSpeed; i += 1000 {
wheel.Forward(i)
time.Sleep(time.Millisecond * 100)
}
@@ -42,7 +30,7 @@ func main() {
time.Sleep(time.Millisecond * 1000)
println("Backward")
for i = 0; i < maxSpeed; i += 10 {
for i = 0; i < maxSpeed; i += 1000 {
wheel.Backward(i)
time.Sleep(time.Millisecond * 100)
}
+6 -25
View File
@@ -8,38 +8,19 @@ import (
)
const (
maxSpeed = 100
maxSpeed = 30000
)
func main() {
machine.D11.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.D12.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.InitPWM()
err := machine.TCC0.Configure(machine.PWMConfig{})
if err != nil {
println(err.Error())
return
}
ca, err := machine.TCC0.Channel(machine.D11)
if err != nil {
println(err.Error())
return
}
cb, err := machine.TCC0.Channel(machine.D12)
if err != nil {
println(err.Error())
return
}
wheel := l9110x.NewWithSpeed(ca, cb, machine.TCC0)
wheel := l9110x.NewWithSpeed(machine.PWM{machine.D11}, machine.PWM{machine.D12})
wheel.Configure()
for i := 0; i <= 10; i++ {
println("Forward")
var i uint32
for i = 0; i < maxSpeed; i += 10 {
var i uint16
for i = 0; i < maxSpeed; i += 1000 {
wheel.Forward(i)
time.Sleep(time.Millisecond * 100)
}
@@ -49,7 +30,7 @@ func main() {
time.Sleep(time.Millisecond * 1000)
println("Backward")
for i = 0; i < maxSpeed; i += 10 {
for i = 0; i < maxSpeed; i += 1000 {
wheel.Backward(i)
time.Sleep(time.Millisecond * 100)
}
-135
View File
@@ -1,135 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/max72xx"
)
// example for a 4 digit 7 segment display
func main() {
// Pins for Arduino Nano 33 IOT
err := machine.SPI0.Configure(machine.SPIConfig{
SDO: machine.D11, // default SDO pin
SCK: machine.D13, // default sck pin
LSBFirst: false,
Frequency: 10000000,
})
if err != nil {
println(err.Error())
}
driver := max72xx.NewDevice(machine.SPI0, machine.D6)
driver.Configure()
digitNumber := 4
driver.StopDisplayTest()
driver.SetDecodeMode(4)
driver.SetScanLimit(4)
driver.StopShutdownMode()
for i := 1; i < int(digitNumber); i++ {
driver.WriteCommand(byte(i), byte(Blank))
}
for {
for _, character := range characters {
println("writing", "characterValue:", character.String())
driver.WriteCommand(byte(4), byte(character))
driver.WriteCommand(byte(3), byte(character))
driver.WriteCommand(byte(2), byte(character))
driver.WriteCommand(byte(1), byte(character))
time.Sleep(500 * time.Millisecond)
}
time.Sleep(time.Second)
}
}
var characters = []Character{
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Dash,
E,
H,
L,
P,
Blank,
Dot,
}
// Each bit translates to a pin, which is driven high or low
type Character byte
func (char Character) String() string {
switch char {
case Zero:
return "0"
case One:
return "1"
case Two:
return "2"
case Three:
return "3"
case Four:
return "4"
case Five:
return "5"
case Six:
return "6"
case Seven:
return "7"
case Eight:
return "8"
case Nine:
return "9"
case Dash:
return "-"
case E:
return "E"
case H:
return "H"
case L:
return "L"
case P:
return "P"
case Blank:
return ""
case Dot:
return "."
}
return ""
}
const (
Zero Character = 0 //126
One Character = 1 //48
Two Character = 2 // 109
Three Character = 3 // 121
Four Character = 4
Five Character = 5
Six Character = 6
Seven Character = 7
Eight Character = 8
Nine Character = 9
Dash Character = 10
E Character = 11
H Character = 12
L Character = 13
P Character = 14
Blank Character = 15
Dot Character = 128
)
-45
View File
@@ -1,45 +0,0 @@
// This example demonstrates putting several mcp23017 devices together into
// a single virtual I/O array.
package main
import (
"machine"
"tinygo.org/x/drivers/mcp23017"
)
func main() {
err := machine.I2C0.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_400KHZ,
})
if err != nil {
panic(err)
}
// Assume the devices are at addresses 0x20, 0x21
dev, err := mcp23017.NewI2CDevices(machine.I2C0, 0x20, 0x21)
if err != nil {
panic(err)
}
// Configure pin 0 for input and all the others for output.
if err := dev.SetModes([]mcp23017.PinMode{
mcp23017.Input | mcp23017.Pullup,
mcp23017.Output,
}); err != nil {
panic(err)
}
input := dev.Pin(0)
// Make a mask that represents all the output pins.
// Note that this leverages the driver behaviour which replicates the highest bit in
// the last slice element (1 in this case) to all other pins
outputMask := mcp23017.PinSlice{^mcp23017.Pins(1 << 0)} // All except pin 0
inputVal, err := input.Get()
if err != nil {
panic(err)
}
println("input value: ", inputVal)
// Set the values of all the output pins.
err = dev.SetPins(mcp23017.PinSlice{0b1011011_01101110, 0b11111101_11100110}, outputMask)
if err != nil {
panic(err)
}
}
-39
View File
@@ -1,39 +0,0 @@
package main
import (
"machine"
"tinygo.org/x/drivers/mcp23017"
)
func main() {
err := machine.I2C0.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_400KHZ,
})
if err != nil {
panic(err)
}
dev, err := mcp23017.NewI2C(machine.I2C0, 0x20)
if err != nil {
panic(err)
}
// Configure pin 0 for input and all the others for output.
if err := dev.SetModes([]mcp23017.PinMode{
mcp23017.Input | mcp23017.Pullup,
mcp23017.Output,
}); err != nil {
panic(err)
}
input := dev.Pin(0)
outputMask := ^mcp23017.Pins(1 << 0) // All except pin 0
inputVal, err := input.Get()
if err != nil {
panic(err)
}
println("input value: ", inputVal)
// Set the values of all the output pins.
err = dev.SetPins(0b1011011_01101110, outputMask)
if err != nil {
panic(err)
}
}
-55
View File
@@ -1,55 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/mcp2515"
)
var (
spi = machine.SPI0
csPin = machine.D5
)
func main() {
spi.Configure(machine.SPIConfig{
Frequency: 115200,
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Mode: 0})
can := mcp2515.New(spi, csPin)
can.Configure()
err := can.Begin(mcp2515.CAN500kBps, mcp2515.Clock8MHz)
if err != nil {
failMessage(err.Error())
}
for {
err := can.Tx(0x111, 8, []byte{0x00, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA})
if err != nil {
failMessage(err.Error())
}
if can.Received() {
msg, err := can.Rx()
if err != nil {
failMessage(err.Error())
}
fmt.Printf("CAN-ID: %03X dlc: %d data: ", msg.ID, msg.Dlc)
for _, b := range msg.Data {
fmt.Printf("%02X ", b)
}
fmt.Print("\r\n")
}
time.Sleep(time.Millisecond * 500)
}
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
-74
View File
@@ -1,74 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/p1am"
)
func main() {
for {
if err := loop(); err != nil {
fmt.Printf("loop failed, retrying: %v\n", err)
time.Sleep(500 * time.Millisecond)
}
}
}
func loop() error {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sw := machine.SWITCH
sw.Configure(machine.PinConfig{Mode: machine.PinInput})
if err := p1am.Controller.Initialize(); err != nil {
return fmt.Errorf("initializing controller: %w", err)
}
version, err := p1am.Controller.Version()
if err != nil {
return fmt.Errorf("fetching base controller version: %w", err)
}
fmt.Printf("Base controller version: %d.%d.%d\n", version[0], version[1], version[2])
for i := 1; i <= p1am.Controller.Slots; i++ {
slot := p1am.Controller.Slot(i)
fmt.Printf("Slot %d: ID 0x%08x, Props %+v\n", i, slot.ID, slot.Props)
}
slot1 := p1am.Controller.Slot(1)
var lastInput uint32
state := sw.Get()
for {
if active, err := p1am.Controller.Active(); err != nil || !active {
return fmt.Errorf("controller active %v: %v", active, err)
}
if state != sw.Get() {
state = sw.Get()
fmt.Printf("New switch state: %v\n", state)
if slot1.Props.DO > 0 {
if err := slot1.Channel(1).WriteDiscrete(state); err != nil {
return err
}
}
}
if slot1.Props.DI > 0 {
sstate, err := slot1.ReadDiscrete()
if err != nil {
return fmt.Errorf("reading slot: %w", err)
}
if sstate != lastInput {
lastInput = sstate
fmt.Printf("new DI state: %#b\n", sstate)
}
}
if state {
led.High()
} else {
led.Low()
}
time.Sleep(time.Millisecond * 10)
}
return nil
}
-45
View File
@@ -1,45 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
time.Sleep(3 * time.Second)
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 50, 0, time.UTC))
rtc.SetAlarm(time.Date(2006, 1, 2, 15, 5, 0, 0, time.UTC))
rtc.EnableAlarmInterrupt()
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
if rtc.AlarmTriggered() {
fmt.Printf("alarm triggered\r\n")
rtc.ClearAlarm()
}
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
-31
View File
@@ -1,31 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
for {
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1HZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32HZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1KHZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32KHZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_DISABLE)
time.Sleep(3 * time.Second)
}
}
-36
View File
@@ -1,36 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
-46
View File
@@ -1,46 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
time.Sleep(3 * time.Second)
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
rtc.SetTimer(15 * time.Second)
rtc.EnableTimerInterrupt()
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
if rtc.TimerTriggered() {
fmt.Printf("timer triggered\r\n")
rtc.ClearTimer()
rtc.SetTimer(10 * time.Second)
}
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
-363
View File
@@ -1,363 +0,0 @@
package main
import (
"fmt"
"io"
"machine"
"os"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers/sdcard"
)
const consoleBufLen = 64
const storageBufLen = 1024
var (
debug = false
input [consoleBufLen]byte
store [storageBufLen]byte
console = machine.Serial
dev *sdcard.Device
commands map[string]cmdfunc = map[string]cmdfunc{
"": cmdfunc(noop),
"help": cmdfunc(help),
"dbg": cmdfunc(dbg),
"erase": cmdfunc(erase),
"lsblk": cmdfunc(lsblk),
"write": cmdfunc(write),
"xxd": cmdfunc(xxd),
}
his history
)
type history struct {
buf [32]string
wp int
idx int
}
func (h *history) Add(cmd string) {
if len(cmd) == 0 {
h.idx = h.wp
return
}
if h.wp == len(h.buf)-1 {
for i := 1; i < len(h.buf); i++ {
h.buf[i-1] = h.buf[i]
}
h.wp--
}
h.buf[h.wp] = cmd
h.wp++
h.idx = h.wp
}
func (h *history) PeekPrev() string {
if h.idx > 0 {
h.idx--
}
return h.buf[h.idx]
}
func (h *history) PeekNext() string {
if h.idx < h.wp {
h.idx++
}
return h.buf[h.idx]
}
type cmdfunc func(argv []string)
const (
StateInput = iota
StateEscape
StateEscBrc
StateCSI
)
func RunFor(device *sdcard.Device) {
dev = device
prompt()
var state = StateInput
for i := 0; ; {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if debug {
fmt.Printf("\rdata: %x, his.idx: %d\r\n\r", data, his.idx)
prompt()
console.Write(input[:i])
}
switch state {
case StateInput:
switch data {
case 0x8:
fallthrough
case 0x7f: // this is probably wrong... works on my machine tho :)
// backspace
if i > 0 {
i -= 1
console.Write([]byte{0x8, 0x20, 0x8})
}
case 13:
// return key
console.Write([]byte("\r\n"))
runCommand(string(input[:i]))
his.Add(string(input[:i]))
prompt()
i = 0
continue
case 27:
// escape
state = StateEscape
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
if i < (consoleBufLen - 1) {
console.WriteByte(data)
input[i] = data
i++
}
}
}
case StateEscape:
switch data {
case 0x5b:
state = StateEscBrc
default:
state = StateInput
}
case StateEscBrc:
switch data {
case 0x41:
// up
println()
prompt()
cmd := his.PeekPrev()
i = len(cmd)
copy(input[:i], []byte(cmd))
console.Write(input[:i])
state = StateInput
case 0x42:
//down
println()
prompt()
cmd := his.PeekNext()
i = len(cmd)
copy(input[:i], []byte(cmd))
console.Write(input[:i])
state = StateInput
default:
// TODO: handle escape sequences
state = StateInput
}
default:
// TODO: handle escape sequences
state = StateInput
}
} else {
time.Sleep(1 * time.Millisecond)
}
}
}
func runCommand(line string) {
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
cmd := argv[0]
cmdfn, ok := commands[cmd]
if !ok {
println("unknown command: " + line)
return
}
cmdfn(argv)
}
func noop(argv []string) {}
func help(argv []string) {
fmt.Printf("help\r\n")
fmt.Printf("dbg\r\n")
fmt.Printf("erase\r\n")
fmt.Printf("lsblk\r\n")
fmt.Printf("write <hex offset> <bytes>\r\n")
fmt.Printf("xxd <start address> <length>\r\n")
}
func dbg(argv []string) {
if debug {
debug = false
println("Console debbuging off")
} else {
debug = true
println("Console debbuging on")
}
}
func lsblk(argv []string) {
csd := dev.CSD
sectors, err := csd.Sectors()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
return
}
cid := dev.CID
fmt.Printf(
"\r\n-------------------------------------\r\n"+
" Device Information: \r\n"+
"-------------------------------------\r\n"+
" JEDEC ID: %v\r\n"+
" Serial: %v\r\n"+
" Status 1: %02x\r\n"+
" Status 2: %02x\r\n"+
" \r\n"+
" Max clock speed (MHz): %d\r\n"+
" Has Sector Protection: %t\r\n"+
" Supports Fast Reads: %t\r\n"+
" Supports QSPI Reads: %t\r\n"+
" Supports QSPI Write: %t\r\n"+
" Write Status Split: %t\r\n"+
" Single Status Byte: %t\r\n"+
"-Sectors: %d\r\n"+
"-Bytes (Sectors * 512) %d\r\n"+
"-ManufacturerID %02X\r\n"+
"-OEMApplicationID %04X\r\n"+
"-ProductName %s\r\n"+
"-ProductVersion %s\r\n"+
"-ProductSerialNumber %08X\r\n"+
"-ManufacturingYear %02X\r\n"+
"-ManufacturingMonth %02X\r\n"+
"-Always1 %d\r\n"+
"-CRC %02X\r\n"+
"-------------------------------------\r\n\r\n",
"attrs.JedecID", // attrs.JedecID,
cid.ProductSerialNumber, // serialNumber1,
0, // status1,
0, // status2,
csd.TRAN_SPEED, // attrs.MaxClockSpeedMHz,
false, // attrs.HasSectorProtection,
false, // attrs.SupportsFastRead,
false, // attrs.SupportsQSPI,
false, // attrs.SupportsQSPIWrites,
false, // attrs.WriteStatusSplit,
false, // attrs.SingleStatusByte,
sectors,
csd.Size(),
cid.ManufacturerID,
cid.OEMApplicationID,
cid.ProductName,
cid.ProductVersion,
cid.ProductSerialNumber,
cid.ManufacturingYear,
cid.ManufacturingMonth,
cid.Always1,
cid.CRC,
)
}
func erase(argv []string) {
fmt.Printf("erase - not impl\r\n")
}
var writeBuf [256]byte
func write(argv []string) {
if len(argv) < 3 {
println("usage: write <hex offset> <bytes>")
return
}
var err error
var addr uint64 = 0x0
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
buf := writeBuf[:0]
for i := 0; i < len(argv[2]); i += 2 {
var b uint64
if b, err = strconv.ParseUint(argv[2][i:i+2], 16, 8); err != nil {
println("Invalid bytes: " + err.Error() + "\r\n")
return
}
buf = append(buf, byte(b))
}
if _, err = dev.WriteAt(buf, int64(addr)); err != nil {
println("Write error: " + err.Error() + "\r\n")
}
}
func xxd(argv []string) {
var err error
var addr uint64 = 0x0
var size int = 64
switch len(argv) {
case 3:
if size, err = strconv.Atoi(argv[2]); err != nil {
println("Invalid size argument: " + err.Error() + "\r\n")
return
}
if size > storageBufLen || size < 1 {
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", storageBufLen)
return
}
fallthrough
case 2:
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
fallthrough
case 1:
// no args supplied, so nothing to do here, just use the defaults
default:
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
return
}
buf := store[0:size]
_, err = dev.ReadAt(buf, int64(addr))
if err != nil {
fmt.Printf("xxd err : %s\r\n", err.Error())
}
xxdfprint(os.Stdout, uint32(addr), buf)
}
func xxdfprint(w io.Writer, offset uint32, b []byte) {
var l int
var buf16 = make([]byte, 16)
for i, c := 0, len(b); i < c; i += 16 {
l = i + 16
if l >= c {
l = c
}
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
for j, n := 0, l-i; j < 16; j++ {
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
buf16[j] = '.'
} else {
buf16[j] = b[i+j]
}
}
console.Write(buf16)
println()
}
}
func prompt() {
print("==> ")
}
-17
View File
@@ -1,17 +0,0 @@
// +build feather_m4 feather_m4_can feather_nrf52840
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D10
ledPin = machine.LED
}
@@ -1,17 +0,0 @@
// +build grandcentral-m4
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_CS_PIN
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build atsamd21,!p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D2
ledPin = machine.LED
}
-51
View File
@@ -1,51 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/sdcard"
)
var (
spi machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
csPin machine.Pin
ledPin machine.Pin
)
func main() {
waitSerial()
fmt.Printf("sdcard console\r\n")
led := ledPin
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
err := sd.Configure()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
for {
time.Sleep(time.Hour)
}
}
go RunFor(&sd)
for {
led.High()
time.Sleep(200 * time.Millisecond)
led.Low()
time.Sleep(200 * time.Millisecond)
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
-17
View File
@@ -1,17 +0,0 @@
// +build p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_SS_PIN
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build pygamer
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D4
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build pyportal
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D32 // SD_CS
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build wioterminal
package main
import (
"machine"
)
func init() {
spi = machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
csPin = machine.SS2
ledPin = machine.LED
}
-519
View File
@@ -1,519 +0,0 @@
// +build tinygo
package console
import (
"fmt"
"io"
"machine"
"os"
"strconv"
"strings"
"time"
"github.com/tinygo-org/tinyfs"
)
const consoleBufLen = 64
const startBlock = 0
const blockCount = 0
var (
debug = false
input [consoleBufLen]byte
console = machine.Serial
readyLED = machine.LED
flashdev tinyfs.BlockDevice
fs tinyfs.Filesystem
currdir = "/"
commands = map[string]cmdfunc{
"": noop,
"dbg": dbg,
"lsblk": lsblk,
"mount": mount,
"umount": umount,
"format": format,
"xxd": xxd,
"ls": ls,
"samples": samples,
"mkdir": mkdir,
"cat": cat,
"create": create,
"write": write,
"rm": rm,
}
)
type cmdfunc func(argv []string)
const (
StateInput = iota
StateEscape
StateEscBrc
StateCSI
)
func RunFor(dev tinyfs.BlockDevice, filesys tinyfs.Filesystem) {
flashdev = dev
fs = filesys
readyLED.Configure(machine.PinConfig{Mode: machine.PinOutput})
readyLED.High()
readyLED.Low()
println("SPI Configured. Reading flash info")
/*
lfsConfig := flashlfs.NewConfig()
if blockCount == 0 {
lfsConfig.BlockCount = (flashdev.Attrs().TotalSize / lfsConfig.BlockSize) - startBlock
} else {
lfsConfig.BlockCount = blockCount
}
println("Start block:", startBlock)
println("Block count:", lfsConfig.BlockCount)
blockdev = flashlfs.NewBlockDevice(flashdev, startBlock, lfsConfig.BlockSize)
*/
prompt()
var state = StateInput
for i := 0; ; {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if debug {
fmt.Printf("\rdata: %x\r\n\r", data)
prompt()
console.Write(input[:i])
}
switch state {
case StateInput:
switch data {
case 0x8:
fallthrough
case 0x7f: // this is probably wrong... works on my machine tho :)
// backspace
if i > 0 {
i -= 1
console.Write([]byte{0x8, 0x20, 0x8})
}
case 13:
// return key
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if data != 10 {
println("\r\nunexpected: \r", int(data))
}
}
console.Write([]byte("\r\n"))
runCommand(string(input[:i]))
prompt()
i = 0
continue
case 27:
// escape
state = StateEscape
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
if i < (consoleBufLen - 1) {
console.WriteByte(data)
input[i] = data
i++
}
}
}
case StateEscape:
switch data {
case 0x5b:
state = StateEscBrc
default:
state = StateInput
}
default:
// TODO: handle escape sequences
state = StateInput
}
}
}
}
func runCommand(line string) {
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
cmd := argv[0]
cmdfn, ok := commands[cmd]
if !ok {
println("unknown command: " + line)
return
}
cmdfn(argv)
}
func noop(argv []string) {}
func dbg(argv []string) {
if debug {
debug = false
println("Console debugging off")
} else {
debug = true
println("Console debugging on")
}
}
func lsblk(argv []string) {
fmt.Printf("lsblk : not implement\r\n")
}
func mount(argv []string) {
if err := fs.Mount(); err != nil {
println("Could not mount LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully mounted LittleFS filesystem.\r\n")
}
}
func format(argv []string) {
if err := fs.Format(); err != nil {
println("Could not format LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully formatted LittleFS filesystem.\r\n")
}
}
func umount(argv []string) {
if err := fs.Unmount(); err != nil {
println("Could not unmount LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully unmounted LittleFS filesystem.\r\n")
}
}
/*
var err error
if fatfs == nil {
fatfs, err = fat.New(fatdisk)
if err != nil {
fatfs = nil
println("could not load FAT filesystem: " + err.Error() + "\r\n")
}
fmt.Printf("loaded fs\r\n")
}
if rootdir == nil {
rootdir, err = fatfs.RootDir()
if err != nil {
rootdir = nil
println("could not load rootdir: " + err.Error() + "\r\n")
}
fmt.Printf("loaded rootdir\r\n")
}
if currdir == nil {
currdir = rootdir
}
*/
func ls(argv []string) {
path := "/"
if len(argv) > 1 {
path = strings.TrimSpace(argv[1])
}
dir, err := fs.Open(path)
if err != nil {
fmt.Printf("Could not open directory %s: %v\r\n", path, err)
return
}
defer dir.Close()
infos, err := dir.Readdir(0)
_ = infos
if err != nil {
fmt.Printf("Could not read directory %s: %v\r\n", path, err)
return
}
for _, info := range infos {
s := "-rwxrwxrwx"
if info.IsDir() {
s = "drwxrwxrwx"
}
fmt.Printf("%s %5d %s\r\n", s, info.Size(), info.Name())
}
}
func mkdir(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying mkdir to " + tgt)
}
if tgt == "" {
println("Usage: mkdir <target dir>")
return
}
err := fs.Mkdir(tgt, 0777)
if err != nil {
println("Could not mkdir " + tgt + ": " + err.Error())
}
}
func rm(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying rm to " + tgt)
}
if tgt == "" {
println("Usage: rm <target dir>")
return
}
err := fs.Remove(tgt)
if err != nil {
println("Could not rm " + tgt + ": " + err.Error())
}
}
func samples(argv []string) {
buf := make([]byte, 90)
for i := 0; i < 5; i++ {
name := fmt.Sprintf("file%d.txt", i)
if bytes, err := createSampleFile(name, buf); err != nil {
fmt.Printf("%s\r\n", err)
return
} else {
fmt.Printf("wrote %d bytes to %s\r\n", bytes, name)
}
}
}
func create(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying create to " + tgt)
}
buf := make([]byte, 90)
if bytes, err := createSampleFile(tgt, buf); err != nil {
fmt.Printf("%s\r\n", err)
return
} else {
fmt.Printf("wrote %d bytes to %s\r\n", bytes, tgt)
}
}
func write(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying receive to " + tgt)
}
buf := make([]byte, 1)
f, err := fs.OpenFile(tgt, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
if err != nil {
fmt.Printf("error opening %s: %s\r\n", tgt, err.Error())
return
}
defer f.Close()
var n int
for {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
switch data {
case 0x04:
fmt.Printf("wrote %d bytes to %s\r\n", n, tgt)
return
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
console.WriteByte(data)
}
buf[0] = data
if _, err := f.Write(buf); err != nil {
fmt.Printf("\nerror writing: %s\r\n", err)
return
}
n++
}
}
}
}
func createSampleFile(name string, buf []byte) (int, error) {
for j := uint8(0); j < uint8(len(buf)); j++ {
buf[j] = 0x20 + j
}
f, err := fs.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
if err != nil {
return 0, fmt.Errorf("error opening %s: %s", name, err.Error())
}
defer f.Close()
bytes, err := f.Write(buf)
if err != nil {
return 0, fmt.Errorf("error writing %s: %s", name, err.Error())
}
return bytes, nil
}
/*
func cd(argv []string) {
if fatfs == nil || rootdir == nil {
mnt(nil)
}
if len(argv) == 1 {
currdir = rootdir
return
}
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying to cd to " + tgt)
}
if tgt == "" {
println("Usage: cd <target dir>")
return
}
if debug {
println("Getting entry")
}
entry := currdir.Entry(tgt)
if entry == nil {
println("File not found: " + tgt)
return
}
if !entry.IsDir() {
println("Not a directory: " + tgt)
return
}
if debug {
println("Getting dir")
}
cd, err := entry.Dir()
if err != nil {
println("Could not cd to " + tgt + ": " + err.Error())
}
currdir = cd
}
*/
func cat(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying to cat to " + tgt)
}
if tgt == "" {
println("Usage: cat <target dir>")
return
}
if debug {
println("Getting entry")
}
f, err := fs.Open(tgt)
if err != nil {
println("Could not open: " + err.Error())
return
}
defer f.Close()
if f.IsDir() {
println("Not a file: " + tgt)
return
}
off := 0x0
buf := make([]byte, 64)
for {
n, err := f.Read(buf)
if err != nil {
if err == io.EOF {
break
}
println("Error reading " + tgt + ": " + err.Error())
time.Sleep(1 * time.Second)
}
xxdfprint(os.Stdout, uint32(off), buf[:n])
off += n
}
}
func xxd(argv []string) {
var err error
var addr uint64 = 0x0
var size int = 64
switch len(argv) {
case 3:
if size, err = strconv.Atoi(argv[2]); err != nil {
println("Invalid size argument: " + err.Error() + "\r\n")
return
}
if size > 512 || size < 1 {
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", 512)
return
}
fallthrough
case 2:
/*
if argv[1][:2] != "0x" {
println("Invalid hex address (should start with 0x)")
return
}
*/
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
fallthrough
case 1:
// no args supplied, so nothing to do here, just use the defaults
default:
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
return
}
buf := make([]byte, size)
//bsz := uint64(flash.SectorSize)
//blockdev.ReadBlock(uint32(addr/bsz), uint32(addr%bsz), buf)
flashdev.ReadAt(buf, int64(addr))
xxdfprint(os.Stdout, uint32(addr), buf)
}
func xxdfprint(w io.Writer, offset uint32, b []byte) {
var l int
var buf16 = make([]byte, 16)
for i, c := 0, len(b); i < c; i += 16 {
l = i + 16
if l >= c {
l = c
}
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
for j, n := 0, l-i; j < 16; j++ {
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
buf16[j] = '.'
} else {
buf16[j] = b[i+j]
}
}
console.Write(buf16)
println()
}
}
func prompt() {
print("==> ")
}
-17
View File
@@ -1,17 +0,0 @@
// +build feather_m4 feather_m4_can feather_nrf52840
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D10
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build grandcentral-m4
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_CS_PIN
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build atsamd21,!p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D2
ledPin = machine.LED
}
-49
View File
@@ -1,49 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"github.com/tinygo-org/tinyfs/fatfs"
"tinygo.org/x/drivers/examples/sdcard/tinyfs/console"
"tinygo.org/x/drivers/sdcard"
)
var (
spi machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
csPin machine.Pin
ledPin machine.Pin
)
func main() {
waitSerial()
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
err := sd.Configure()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
for {
time.Sleep(time.Hour)
}
}
filesystem := fatfs.New(&sd)
// Configure FATFS with sector size (must match value in ff.h - use 512)
filesystem.Configure(&fatfs.Config{
SectorSize: 512,
})
console.RunFor(&sd, filesystem)
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
-17
View File
@@ -1,17 +0,0 @@
// +build p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_SS_PIN
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build pygamer
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D4
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build pyportal
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D32 // SD_CS
ledPin = machine.LED
}
-17
View File
@@ -1,17 +0,0 @@
// +build wioterminal
package main
import (
"machine"
)
func init() {
spi = machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
csPin = machine.SS2
ledPin = machine.LED
}
-43
View File
@@ -1,43 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/servo"
)
// Configuration for the Arduino Uno.
// Please change the PWM and pin if you want to try this example on a different
// board.
var (
pwm = machine.Timer1
pin = machine.D9
)
func main() {
s, err := servo.New(pwm, pin)
if err != nil {
for {
println("could not configure servo")
time.Sleep(time.Second)
}
return
}
println("setting to 0°")
s.SetMicroseconds(1000)
time.Sleep(3 * time.Second)
println("setting to 45°")
s.SetMicroseconds(1500)
time.Sleep(3 * time.Second)
println("setting to 90°")
s.SetMicroseconds(2000)
time.Sleep(3 * time.Second)
for {
time.Sleep(time.Second)
}
}
-60
View File
@@ -1,60 +0,0 @@
// This example shows how to use 128x64 display over I2C
// Tested on Seeeduino XIAO Expansion Board https://wiki.seeedstudio.com/Seeeduino-XIAO-Expansion-Board/
//
// According to manual, I2C address of the display is 0x78, but that's 8-bit address.
// TinyGo operates on 7-bit addresses and respective 7-bit address would be 0x3C, which we use below.
//
// To learn more about different types of I2C addresses, please see following page
// https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing
package main
import (
"machine"
"image/color"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_400KHZ,
})
display := ssd1306.NewI2C(machine.I2C0)
display.Configure(ssd1306.Config{
Address: 0x3C,
Width: 128,
Height: 64,
})
display.ClearDisplay()
x := int16(0)
y := int16(0)
deltaX := int16(1)
deltaY := int16(1)
for {
pixel := display.GetPixel(x, y)
c := color.RGBA{255, 255, 255, 255}
if pixel {
c = color.RGBA{0, 0, 0, 255}
}
display.SetPixel(x, y, c)
display.Display()
x += deltaX
y += deltaY
if x == 0 || x == 127 {
deltaX = -deltaX
}
if y == 0 || y == 63 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
package main
package ssd1331
import (
"machine"
+1 -1
View File
@@ -1,4 +1,4 @@
package main
package ssd1351
import (
"machine"
-40
View File
@@ -1,40 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/tm1637"
)
func main() {
tm := tm1637.New(machine.D2, machine.D3, 7) // clk, dio, brightness
tm.Configure()
tm.ClearDisplay()
tm.DisplayText([]byte("Tiny"))
time.Sleep(time.Millisecond * 1000)
tm.ClearDisplay()
tm.DisplayChr(byte('G'), 1)
tm.DisplayDigit(0, 2) // looks like O
time.Sleep(time.Millisecond * 1000)
tm.DisplayClock(12, 59, true)
for i := uint8(0); i < 8; i++ {
tm.Brightness(i)
time.Sleep(time.Millisecond * 200)
}
i := int16(0)
for {
tm.DisplayNumber(i)
i++
time.Sleep(time.Millisecond * 50)
}
}
-33
View File
@@ -1,33 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/tone"
)
var (
// Configuration for the Adafruit Circuit Playground Bluefruit.
pwm = machine.PWM0
pin = machine.D12
)
func main() {
speaker, err := tone.New(pwm, pin)
if err != nil {
println("failed to configure PWM")
return
}
// Two tone siren.
for {
println("nee")
speaker.SetNote(tone.B5)
time.Sleep(time.Second / 2)
println("naw")
speaker.SetNote(tone.A5)
time.Sleep(time.Second / 2)
}
}
-146
View File
@@ -1,146 +0,0 @@
// This example connects to Access Point and prints some info
package main
import (
"machine"
"strconv"
"time"
"tinygo.org/x/drivers/wifinina"
)
// access point info
const ssid = ""
const pass = ""
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *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,
})
adaptor = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
println("----------------------------------------")
printSSID()
printRSSI()
printMac()
printIPs()
printTime()
time.Sleep(10 * time.Second)
}
}
func printSSID() {
print("SSID: ")
ssid, err := adaptor.GetCurrentSSID()
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
println(ssid)
}
func printRSSI() {
print("RSSI: ")
rssi, err := adaptor.GetCurrentRSSI()
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
println(strconv.Itoa(int(rssi)))
}
func printIPs() {
ip, subnet, gateway, err := adaptor.GetIP()
if err != nil {
println("IP: Unknown (error: ", err.Error(), ")")
return
}
println("IP: ", ip.String())
println("Subnet: ", subnet.String())
println("Gateway: ", gateway.String())
}
func printTime() {
print("Time: ")
t, err := adaptor.GetTime()
for {
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
if t != 0 {
break
}
time.Sleep(time.Second)
t, err = adaptor.GetTime()
}
println(time.Unix(int64(t), 0).String())
}
func printMac() {
print("MAC: ")
mac, err := adaptor.GetMACAddress()
if err != nil {
println("Unknown (", err.Error(), ")")
}
println(mac.String())
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
println("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
println("Connection status: " + st.String())
time.Sleep(1 * time.Second)
st, _ = adaptor.GetConnectionStatus()
}
println("Connected.")
}
+6 -2
View File
@@ -35,7 +35,10 @@ const server = "tcp://test.mosquitto.org:1883"
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -45,6 +48,7 @@ var (
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Configure SPI for 8Mhz, Mode 0, MSB First
@@ -90,7 +94,7 @@ func main() {
println(err.Error())
}
}
time.Sleep(100 * time.Millisecond)
time.Sleep(1 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
+6 -1
View File
@@ -32,8 +32,12 @@ const server = "tcp://test.mosquitto.org:1883"
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -51,6 +55,7 @@ func subHandler(client mqtt.Client, msg mqtt.Message) {
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Configure SPI for 8Mhz, Mode 0, MSB First
+12 -29
View File
@@ -23,41 +23,33 @@ const ntpHost = "129.6.15.29"
const NTP_PACKET_SIZE = 48
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
b = make([]byte, NTP_PACKET_SIZE)
)
func setup() {
func main() {
// Init esp32
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
machine.NINA_SPI.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
adaptor = wifinina.New(spi,
// these are the default pins for the Arduino Nano33 IoT.
adaptor = wifinina.New(machine.NINA_SPI,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
// connect to access point
connectToAP()
// now make UDP connection
@@ -88,13 +80,10 @@ func main() {
}
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting UDP...")
conn.Close()
println("Done.")
}
func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
@@ -151,12 +140,6 @@ func clearBuffer() {
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
+6 -1
View File
@@ -29,7 +29,10 @@ const serverIP = ""
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -39,6 +42,8 @@ var buf = &bytes.Buffer{}
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
-151
View File
@@ -1,151 +0,0 @@
// This example opens a TCP connection using a device with WiFiNINA firmware
// and sends a HTTPS request to retrieve a webpage
//
// You shall see "strict-transport-security" header in the response,
// this confirms communication is indeed over HTTPS
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
//
package main
import (
"fmt"
"machine"
"strings"
"time"
"tinygo.org/x/drivers/net"
"tinygo.org/x/drivers/net/tls"
"tinygo.org/x/drivers/wifinina"
)
// access point info
const ssid = ""
const pass = ""
// IP address of the server aka "hub". Replace with your own info.
const server = "tinygo.org"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
)
var buf [256]byte
var lastRequestTime time.Time
var conn net.Conn
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,
})
adaptor = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPSRequest()
}
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
println("Read error: " + err.Error())
} else {
print(string(buf[0:n]))
}
}
}
}
func makeHTTPSRequest() {
var err error
if conn != nil {
conn.Close()
}
message("\r\n---------------\r\nDialing TCP connection")
conn, err = tls.Dial("tcp", server, nil)
for ; err != nil; conn, err = tls.Dial("tcp", server, nil) {
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
print("Sending HTTPS request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", strings.Split(server, ":")[0])
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
lastRequestTime = time.Now()
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
message("Connection status: " + st.String())
time.Sleep(1 * time.Second)
st, _ = adaptor.GetConnectionStatus()
}
message("Connected.")
time.Sleep(2 * time.Second)
ip, _, _, err := adaptor.GetIP()
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
message(err.Error())
time.Sleep(1 * time.Second)
}
message(ip.String())
}
func message(msg string) {
println(msg, "\r")
}
+27 -30
View File
@@ -27,7 +27,10 @@ const server = "tinygo.org"
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -38,7 +41,10 @@ var buf [256]byte
var lastRequestTime time.Time
var conn net.Conn
func setup() {
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
@@ -53,33 +59,16 @@ func setup() {
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
}
loop()
}
println("Done.")
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
func readConnection() {
func loop() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
@@ -89,6 +78,9 @@ func readConnection() {
}
}
}
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
}
}
func makeHTTPRequest() {
@@ -106,7 +98,7 @@ func makeHTTPRequest() {
message("\r\n---------------\r\nDialing TCP connection")
conn, err = net.DialTCP("tcp", laddr, raddr)
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
message("Connection failed: " + err.Error())
message("connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
@@ -114,7 +106,7 @@ func makeHTTPRequest() {
print("Sending HTTP request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", server)
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "User-Agent: TinyGo/0.10.0")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
@@ -122,14 +114,19 @@ func makeHTTPRequest() {
lastRequestTime = time.Now()
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
func readLine(conn *net.TCPSerialConn) string {
println("Attempting to read...\r")
b := buf[:]
for expiry := time.Now().Unix() + 10; time.Now().Unix() > expiry; {
if n, err := conn.Read(b); n > 0 && err == nil {
return string(b[0:n])
}
}
return ""
}
// connect to access point
func connectToAP() {
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
+1 -2
View File
@@ -4,7 +4,6 @@ package main
import "machine"
// Replace neo and led in the code below to match the pin
// Replace neo in the code below to match the pin
// that you are using if different.
var neo = machine.D2
var led = machine.LED
+1 -2
View File
@@ -5,7 +5,6 @@ package main
import "machine"
// This is the pin assignment for the Digispark only.
// Replace neo and led in the code below to match the pin
// Replace neo in the code below to match the pin
// that you are using if different.
var neo machine.Pin = 0
var led = machine.LED
+1
View File
@@ -15,6 +15,7 @@ import (
var leds [10]color.RGBA
func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
+2 -3
View File
@@ -1,10 +1,9 @@
// +build !digispark,!arduino,!qtpy
// +build !digispark,!arduino
package main
import "machine"
// Replace neo and led in the code below to match the pin
// Replace neo in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.NEOPIXELS
var led = machine.LED
-16
View File
@@ -1,16 +0,0 @@
// +build qtpy
package main
import "machine"
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.NEOPIXELS
var led = machine.NoPin
func init() {
pwr := machine.NEOPIXELS_POWER
pwr.Configure(machine.PinConfig{Mode: machine.PinOutput})
pwr.High()
}
+2 -1
View File
@@ -290,8 +290,9 @@ func (dev *Device) EraseBlockSize() int64 {
// supports this. The start and len parameters are in block numbers, use
// EraseBlockSize to map addresses to blocks.
func (dev *Device) EraseBlocks(start, len int64) error {
// TODO: maybe combine sector erase operations into block erase operations
for i := start; i < start+len; i++ {
if err := dev.EraseBlock(uint32(i)); err != nil {
if err := dev.EraseSector(uint32(i)); err != nil {
return err
}
}
-6
View File
@@ -5,10 +5,4 @@ go 1.15
require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/frankban/quicktest v1.10.2
github.com/sago35/tinygo-dma v0.0.0-20210610020721-297675ab9b23 // indirect
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8
)
replace (
github.com/sago35/tinygo-dma => ../../sago35/tinygo-dma
)
-7
View File
@@ -9,12 +9,5 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/sago35/tinygo-dma v0.0.0-20210610020721-297675ab9b23 h1:ESMYhe6RQJ2RbBCH2OK1SNyYq3gKoBpI7g07aLjQgJI=
github.com/sago35/tinygo-dma v0.0.0-20210610020721-297675ab9b23/go.mod h1:gXCCsg4cKOJ6NJl7teGN597XgN0hzQJz0Wekayj4k+M=
github.com/tinygo-org/tinyfs v0.0.0-20210514004344-b02c062d12c9 h1:66or7MohOph3xr3gMGCXceLkd+MBoUbV/rPPjl8iQOU=
github.com/tinygo-org/tinyfs v0.0.0-20210514004344-b02c062d12c9/go.mod h1:HGuyo42bGd1zWSuS1gwgyyjN36ZZMlEpwM0vSrglmXc=
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8 h1:pYwuKe1XuNeJnGV1UjeZ0FhuZ5+lapIq1NUmGacbBwo=
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8/go.mod h1:HGuyo42bGd1zWSuS1gwgyyjN36ZZMlEpwM0vSrglmXc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
+3 -2
View File
@@ -4,6 +4,7 @@ package gps // import "tinygo.org/x/drivers/gps"
import (
"encoding/hex"
"errors"
"machine"
"strings"
"time"
@@ -20,13 +21,13 @@ type Device struct {
buffer []byte
bufIdx int
sentence strings.Builder
uart drivers.UART
uart *machine.UART
bus drivers.I2C
address uint16
}
// NewUART creates a new UART GPS connection. The UART must already be configured.
func NewUART(uart drivers.UART) Device {
func NewUART(uart *machine.UART) Device {
return Device{
uart: uart,
buffer: make([]byte, bufferSize),
+1 -11
View File
@@ -57,16 +57,9 @@ func (g *GPIO) SetCommandMode(set bool) {
}
}
// WriteOnly is true if you passed rw in as machine.NoPin
func (g *GPIO) WriteOnly() bool {
return g.rw == machine.NoPin
}
// Write writes len(data) bytes from data to display driver
func (g *GPIO) Write(data []byte) (n int, err error) {
if !g.WriteOnly() {
g.rw.Low()
}
g.rw.Low()
for _, d := range data {
g.write(d)
n++
@@ -96,9 +89,6 @@ func (g *GPIO) Read(data []byte) (n int, err error) {
if len(data) == 0 {
return 0, errors.New("length greater than 0 is required")
}
if g.WriteOnly() {
return 0, errors.New("Read not supported if RW not wired")
}
g.rw.High()
g.reconfigureGPIOMode(machine.PinInput)
for i := 0; i < len(data); i++ {
+9 -60
View File
@@ -11,23 +11,9 @@ import (
"time"
)
const (
// These are the default execution times for the Clear and
// Home commands and everything else.
//
// These are used if RW is passed as machine.NoPin and ignored
// otherwise.
//
// They are set conservatively here and can be tweaked in the
// Config structure.
DefaultClearHomeTime = 80 * time.Millisecond
DefaultInstrExecTime = 80 * time.Microsecond
)
type Buser interface {
io.ReadWriter
SetCommandMode(set bool)
WriteOnly() bool
}
type Device struct {
@@ -42,9 +28,6 @@ type Device struct {
cursor cursor
busyStatus []byte
clearHomeTime time.Duration // time clear/home instructions might take
instrExecTime time.Duration // time all other instructions might take
}
type cursor struct {
@@ -52,18 +35,14 @@ type cursor struct {
}
type Config struct {
Width int16
Height int16
CursorBlink bool
CursorOnOff bool
Font uint8
ClearHomeTime time.Duration // time clear/home instructions might take - use 0 for the default
InstrExecTime time.Duration // time all other instructions might take - use 0 for the default
Width int16
Height int16
CursorBlink bool
CursorOnOff bool
Font uint8
}
// NewGPIO4Bit returns 4bit data length HD44780 driver. Datapins are LCD DB pins starting from DB4 to DB7
//
// If your device has RW set permanently to ground then pass in rw as machine.NoPin
func NewGPIO4Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error) {
const fourBitMode = 4
if len(dataPins) != fourBitMode {
@@ -73,8 +52,6 @@ func NewGPIO4Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error)
}
// NewGPIO8Bit returns 8bit data length HD44780 driver. Datapins are LCD DB pins starting from DB0 to DB7
//
// If your device has RW set permanently to ground then pass in rw as machine.NoPin
func NewGPIO8Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error) {
const eightBitMode = 8
if len(dataPins) != eightBitMode {
@@ -91,8 +68,6 @@ func (d *Device) Configure(cfg Config) error {
if d.width == 0 || d.height == 0 {
return errors.New("width and height must be set")
}
d.clearHomeTime = cfg.ClearHomeTime
d.instrExecTime = cfg.InstrExecTime
memoryMap := uint8(ONE_LINE)
if d.height > 1 {
memoryMap = TWO_LINE
@@ -211,7 +186,7 @@ func (d *Device) SendCommand(command byte) {
d.bus.SetCommandMode(true)
d.bus.Write([]byte{command})
for d.busy(command == DISPLAY_CLEAR || command == CURSOR_HOME) {
for d.Busy() {
}
}
@@ -220,7 +195,7 @@ func (d *Device) sendData(data byte) {
d.bus.SetCommandMode(false)
d.bus.Write([]byte{data})
for d.busy(false) {
for d.Busy() {
}
}
@@ -232,39 +207,13 @@ func (d *Device) CreateCharacter(cgramAddr uint8, data []byte) {
}
}
// busy returns true when hd447890 is busy
// or after the timeout specified
func (d *Device) busy(longDelay bool) bool {
if d.bus.WriteOnly() {
// Can't read busy flag if write only, so sleep a bit then return
if longDelay {
// Note that we sleep like this so the default
// time.Sleep is time.Sleep(constant) as
// time.Sleep(variable) doesn't seem to work on AVR yet
if d.clearHomeTime != 0 {
time.Sleep(d.clearHomeTime)
} else {
time.Sleep(DefaultClearHomeTime)
}
} else {
if d.instrExecTime != 0 {
time.Sleep(d.instrExecTime)
} else {
time.Sleep(DefaultInstrExecTime)
}
}
return false
}
// Busy returns true when hd447890 is busy
func (d *Device) Busy() bool {
d.bus.SetCommandMode(true)
d.bus.Read(d.busyStatus)
return (d.busyStatus[0] & BUSY) > 0
}
// Busy returns true when hd447890 is busy
func (d *Device) Busy() bool {
return d.busy(false)
}
// Size returns the current size of the display.
func (d *Device) Size() (w, h int16) {
return int16(d.width), int16(d.height)
+36 -55
View File
@@ -28,35 +28,6 @@ type Device struct {
rd machine.Pin
}
var cmdBuf [4]byte
var initCmd = []byte{
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
PWCTR1, 1, 0x23, // Power control VRH[5:0]
PWCTR2, 1, 0x10, // Power control SAP[2:0];BT[3:0]
VMCTR1, 2, 0x3e, 0x28, // VCM control
VMCTR2, 1, 0x86, // VCM control2
MADCTL, 1, 0x48, // Memory Access Control
VSCRSADD, 1, 0x00, // Vertical scroll zero
PIXFMT, 1, 0x55,
FRMCTR1, 2, 0x00, 0x18,
DFUNCTR, 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
GAMMASET, 1, 0x01, // Gamma curve selected
GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
SLPOUT, 0x80, // Exit Sleep
DISPON, 0x80, // Display on
0x00, // End of list
}
// Configure prepares display for use
func (d *Device) Configure(config Config) {
@@ -109,6 +80,33 @@ func (d *Device) Configure(config Config) {
delay(150)
}
initCmd := []byte{
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
PWCTR1, 1, 0x23, // Power control VRH[5:0]
PWCTR2, 1, 0x10, // Power control SAP[2:0];BT[3:0]
VMCTR1, 2, 0x3e, 0x28, // VCM control
VMCTR2, 1, 0x86, // VCM control2
MADCTL, 1, 0x48, // Memory Access Control
VSCRSADD, 1, 0x00, // Vertical scroll zero
PIXFMT, 1, 0x55,
FRMCTR1, 2, 0x00, 0x18,
DFUNCTR, 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
GAMMASET, 1, 0x01, // Gamma curve selected
GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
SLPOUT, 0x80, // Exit Sleep
DISPON, 0x80, // Display on
0x00, // End of list
}
for i, c := 0, len(initCmd); i < c; {
cmd := initCmd[i]
if cmd == 0x00 {
@@ -148,24 +146,8 @@ func (d *Device) Display() error {
return nil
}
var err1 = errors.New("rectangle coordinates outside display area")
// DrawRGBBitmap copies an RGB bitmap to the internal buffer at given coordinates
func (d *Device) DrawRGBBitmap(x, y int16, data []uint16, w, h int16) error {
k, i := d.Size()
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
x >= k || (x+w) > k || y >= i || (y+h) > i {
return err1
}
d.setWindow(x, y, w, h)
d.startWrite()
d.driver.write16sl(data)
d.endWrite()
return nil
}
// DrawRGBBitmap8 copies an RGB bitmap to the internal buffer at given coordinates
func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
k, i := d.Size()
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
x >= k || (x+w) > k || y >= i || (y+h) > i {
@@ -173,7 +155,7 @@ func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
}
d.setWindow(x, y, w, h)
d.startWrite()
d.driver.write8sl(data)
d.driver.write16sl(data)
d.endWrite()
return nil
}
@@ -253,8 +235,7 @@ func (d *Device) SetRotation(rotation Rotation) {
case 3:
madctl = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR
}
cmdBuf[0] = madctl
d.sendCommand(MADCTL, cmdBuf[:1])
d.sendCommand(MADCTL, []uint8{madctl})
d.rotation = rotation
}
@@ -285,14 +266,16 @@ func (d *Device) setWindow(x, y, w, h int16) {
//y += d.rowOffset
x1 := x + w - 1
if x != d.x0 || x1 != d.x1 {
cmdBuf[0], cmdBuf[1], cmdBuf[2], cmdBuf[3] = uint8(x>>8), uint8(x), uint8(x1>>8), uint8(x1)
d.sendCommand(CASET, cmdBuf[:4])
d.sendCommand(CASET, []uint8{
uint8(x >> 8), uint8(x), uint8(x1 >> 8), uint8(x1),
})
d.x0, d.x1 = x, x1
}
y1 := y + h - 1
if y != d.y0 || y1 != d.y1 {
cmdBuf[0], cmdBuf[1], cmdBuf[2], cmdBuf[3] = uint8(y>>8), uint8(y), uint8(y1>>8), uint8(y1)
d.sendCommand(PASET, cmdBuf[:4])
d.sendCommand(PASET, []uint8{
uint8(y >> 8), uint8(y), uint8(y1 >> 8), uint8(y1),
})
d.y0, d.y1 = y, y1
}
d.sendCommand(RAMWR, nil)
@@ -317,9 +300,7 @@ func (d *Device) sendCommand(cmd byte, data []byte) {
d.dc.Low()
d.driver.write8(cmd)
d.dc.High()
if data != nil {
d.driver.write8sl(data)
}
d.driver.write8sl(data)
d.endWrite()
}
-128
View File
@@ -1,128 +0,0 @@
// +build !atsamd51,!atsamd21
package ili9341
import (
"device/sam"
"machine"
"unsafe"
dma "github.com/sago35/tinygo-dma"
)
var (
dbg5 = machine.D5
dbg6 = machine.D6
)
func init() {
dbg5.Configure(machine.PinConfig{Mode: machine.PinOutput})
dbg6.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
var buf [64]byte
type spiDriver struct {
bus machine.SPI
}
var (
dmatx *dma.DMA
desc *dma.DMADescriptor
)
func NewSPI(bus machine.SPI, dc, cs, rst machine.Pin) *Device {
from := make([]byte, 256)
for i := range from {
from[i] = byte(i)
}
dmatx = dma.NewDMA(func(d *dma.DMA) {
d.Wait()
return
})
dmatx.SetTrigger(dma.DMAC_CHANNEL_CHCTRLA_TRIGSRC_SERCOM1_TX)
dmatx.SetTriggerAction(sam.DMAC_CHANNEL_CHCTRLA_TRIGACT_BURST)
desc = dmatx.GetDescriptor()
return &Device{
dc: dc,
cs: cs,
rst: rst,
rd: machine.NoPin,
driver: &spiDriver{
bus: bus,
},
}
}
func (pd *spiDriver) configure(config *Config) {
}
func (pd *spiDriver) write8(b byte) {
buf[0] = b
pd.bus.Tx(buf[:1], nil)
}
func (pd *spiDriver) write8n(b byte, n int) {
buf[0] = b
for i := 0; i < n; i++ {
pd.bus.Tx(buf[:1], nil)
}
}
func (pd *spiDriver) write8sl(b []byte) {
if len(b) > 64 {
desc.UpdateDescriptor(dma.DescriptorConfig{
SRC: unsafe.Pointer(&b[0]),
DST: unsafe.Pointer(&pd.bus.Bus.DATA.Reg),
SRCINC: dma.DMAC_SRAM_BTCTRL_SRCINC_ENABLE,
DSTINC: dma.DMAC_SRAM_BTCTRL_DSTINC_DISABLE,
SIZE: uint32(len(b)), // Total size of DMA transfer
BLOCKACT: 1,
})
dmatx.Start()
return
}
pd.bus.Tx(b, nil)
}
func (pd *spiDriver) write16(data uint16) {
buf[0] = uint8(data >> 8)
buf[1] = uint8(data)
pd.bus.Tx(buf[:2], nil)
}
func (pd *spiDriver) write16n(data uint16, n int) {
for i := 0; i < len(buf); i += 2 {
buf[i] = uint8(data >> 8)
buf[i+1] = uint8(data)
}
for i := 0; i < (n >> 5); i++ {
pd.bus.Tx(buf[:], nil)
}
pd.bus.Tx(buf[:n%64], nil)
}
func (pd *spiDriver) write16sl(data []uint16) {
if len(data) > 64 {
desc.UpdateDescriptor(dma.DescriptorConfig{
SRC: unsafe.Pointer(&data[0]),
DST: unsafe.Pointer(&pd.bus.Bus.DATA.Reg),
SRCINC: dma.DMAC_SRAM_BTCTRL_SRCINC_ENABLE,
DSTINC: dma.DMAC_SRAM_BTCTRL_DSTINC_DISABLE,
SIZE: uint32(len(data) * 2), // Total size of DMA transfer
BLOCKACT: 1,
})
dmatx.Start()
return
}
for i, c := 0, len(data); i < c; i++ {
buf[0] = uint8(data[i] >> 8)
buf[1] = uint8(data[i])
pd.bus.Tx(buf[:2], nil)
}
}
-112
View File
@@ -1,112 +0,0 @@
package ina260
import "tinygo.org/x/drivers"
// Device wraps an I2C connection to an INA260 device.
type Device struct {
bus drivers.I2C
Address uint16
}
// Config holds the configuration of the INA260 device.
type Config struct {
// One of AVGMODE_XXX
AverageMode byte
// One of CONVTIME_XXXXUSEC
VoltConvTime byte
// One of CONVTIME_XXXXUSEC
CurrentConvTime byte
// Multiple of MODE_XXXX
Mode byte
}
// New creates a new INA260 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
}
}
// Configure sets up the device.
//
// This only needs to be called to override built-in defaults. By default,
// the device starts with:
//
// * AverageMode = AVGMODE_1
// * VoltConvTime = CONVTIME_1100USEC
// * CurrentConvTime = CONVTIME_1100USEC
// * Mode = MODE_CONTINUOUS | MODE_VOLTAGE | MODE_CURRENT
//
func (d *Device) Configure(cfg Config) {
var val uint16
val = uint16(cfg.AverageMode&0x7) << 9
val |= uint16(cfg.VoltConvTime&0x7) << 6
val |= uint16(cfg.CurrentConvTime&0x7) << 3
val |= uint16(cfg.Mode & 0x7)
d.WriteRegister(REG_CONFIG, val)
}
// Resets the device, setting all registers to default values
func (d *Device) Reset() {
d.WriteRegister(REG_CONFIG, 0x8000)
}
// Connected returns whether an INA260 has been found.
func (d *Device) Connected() bool {
return d.ReadRegister(REG_MANF_ID) == MANF_ID &&
(d.ReadRegister(REG_DIE_ID)&DEVICE_ID_MASK) == DEVICE_ID
}
// Gets the measured current in µA (max resolution 1.25mA)
func (d *Device) Current() int32 {
val := d.ReadRegister(REG_CURRENT)
if val&0x8000 == 0 {
return int32(val) * 1250
}
// Two's complement, convert to signed int
return -(int32(^val) + 1) * 1250
}
// Gets the measured voltage in µV (max resolution 1.25mV)
func (d *Device) Voltage() int32 {
val := d.ReadRegister(REG_BUSVOLTAGE)
if val&0x8000 == 0 {
return int32(val) * 1250
}
// Two's complement, convert to signed int
return -(int32(^val) + 1) * 1250
}
// Gets the measured power in µW (max resolution 10mW)
func (d *Device) Power() int32 {
return int32(d.ReadRegister(REG_POWER)) * 10000
}
// Read a register
func (d *Device) ReadRegister(reg uint8) uint16 {
data := []byte{0, 0}
d.bus.ReadRegister(uint8(d.Address), reg, data)
return (uint16(data[0]) << 8) | uint16(data[1])
}
// Write to a register
func (d *Device) WriteRegister(reg uint8, v uint16) {
data := []byte{0, 0}
data[0] = byte(v >> 8)
data[1] = byte(v & 0xff)
d.bus.WriteRegister(uint8(d.Address), reg, data)
}
-80
View File
@@ -1,80 +0,0 @@
package ina260
import (
"testing"
qt "github.com/frankban/quicktest"
"tinygo.org/x/drivers/tester"
)
func TestDefaultI2CAddress(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
c.Assert(dev.Address, qt.Equals, uint16(Address))
}
func TestConnected(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
bus.AddDevice(fake)
dev := New(bus)
c.Assert(dev.Connected(), qt.Equals, true)
}
func TestVoltage(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_BUSVOLTAGE] = 0x2570
bus.AddDevice(fake)
dev := New(bus)
// Datasheet: 2570h = 11.98V = 11980mV = 11980000uV
c.Assert(dev.Voltage(), qt.Equals, int32(11980000))
}
func TestCurrent(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_CURRENT] = 0x2710
bus.AddDevice(fake)
dev := New(bus)
// Datasheet: 2710h = 12.5A = 12500mA = 12500000uA
c.Assert(dev.Current(), qt.Equals, int32(12500000))
}
func TestPower(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_POWER] = 0x3A7F
bus.AddDevice(fake)
dev := New(bus)
// 3A7Fh = 149.75W = 149750mW = 149750000uW
c.Assert(dev.Power(), qt.Equals, int32(149750000))
}
// defaultRegisters returns the default values for all of the device's registers.
// set TI INA260 datasheet for power-on defaults
func defaultRegisters() map[uint8]uint16 {
return map[uint8]uint16{
REG_CONFIG: 0x6127,
REG_CURRENT: 0x0000,
REG_BUSVOLTAGE: 0x0000,
REG_POWER: 0x0000,
REG_MASKENABLE: 0x0000,
REG_ALERTLIMIT: 0x0000,
REG_MANF_ID: 0x5449,
REG_DIE_ID: 0x2270,
}
}
-50
View File
@@ -1,50 +0,0 @@
package ina260
// The default I2C address for this device.
//
// The actual address is configurable by connecting address pins.
const Address = 0x40
// Registers
const (
REG_CONFIG = 0x00
REG_CURRENT = 0x01
REG_BUSVOLTAGE = 0x02
REG_POWER = 0x03
REG_MASKENABLE = 0x06
REG_ALERTLIMIT = 0x07
REG_MANF_ID = 0xFE
REG_DIE_ID = 0xFF
)
// Well-Known Values
const (
MANF_ID = 0x5449 // TI
DEVICE_ID = 0x2270 // 227h
DEVICE_ID_MASK = 0xFFF0
AVGMODE_1 = 0
AVGMODE_4 = 1
AVGMODE_16 = 2
AVGMODE_64 = 3
AVGMODE_128 = 4
AVGMODE_256 = 5
AVGMODE_512 = 6
AVGMODE_1024 = 7
CONVTIME_140USEC = 0
CONVTIME_204USEC = 1
CONVTIME_332USEC = 2
CONVTIME_588USEC = 3
CONVTIME_1100USEC = 4 // 1.1 ms
CONVTIME_2116USEC = 5 // 2.1 ms
CONVTIME_4156USEC = 6 // 4.2 ms
CONVTIME_8244USEC = 7 // 8.2 ms
MODE_CONTINUOUS = 0x4
MODE_TRIGGERED = 0x0
MODE_VOLTAGE = 0x2
MODE_NO_VOLTAGE = 0x0
MODE_CURRENT = 0x1
MODE_NO_CURRENT = 0x0
)
-107
View File
@@ -1,107 +0,0 @@
package keypad4x4
import (
"machine"
)
// NoKeyPressed is used, when no key was pressed
const NoKeyPressed = 255
// Device is used as 4x4 keypad driver
type Device interface {
Configure()
GetKey() uint8
GetIndices() (int, int)
}
// device is a driver for 4x4 keypads
type device struct {
inputEnabled bool
lastColumn int
lastRow int
columns [4]machine.Pin
rows [4]machine.Pin
mapping [4][4]uint8
}
// takes r4 -r1 pins and c4 - c1 pins
func NewDevice(r4, r3, r2, r1, c4, c3, c2, c1 machine.Pin) Device {
result := &device{}
result.columns = [4]machine.Pin{c4, c3, c2, c1}
result.rows = [4]machine.Pin{r4, r3, r2, r1}
return result
}
// Configure sets the column pins as input and the row pins as output
func (keypad *device) Configure() {
inputConfig := machine.PinConfig{Mode: machine.PinInputPullup}
for i := range keypad.columns {
keypad.columns[i].Configure(inputConfig)
}
outputConfig := machine.PinConfig{Mode: machine.PinOutput}
for i := range keypad.rows {
keypad.rows[i].Configure(outputConfig)
keypad.rows[i].High()
}
keypad.mapping = [4][4]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
{12, 13, 14, 15},
}
keypad.inputEnabled = true
keypad.lastColumn = -1
keypad.lastRow = -1
}
// GetKey returns the code for the given key.
// The codes start with 0 at the upper left end of the keypad and end with 15 at the lower right end of the keypad
// Example:
// 0 1 2 3
// 4 5 6 7
// 8 9 10 11
// 12 13 14 15
// returns 255 for no keyPressed
func (keypad *device) GetKey() uint8 {
row, column := keypad.GetIndices()
if row == -1 && column == -1 {
return NoKeyPressed
}
return keypad.mapping[row][column]
}
// GetIndices returns the position of the pressed key
func (keypad *device) GetIndices() (int, int) {
for rowIndex, rowPin := range keypad.rows {
rowPin.Low()
for columnIndex := range keypad.columns {
columnPin := keypad.columns[columnIndex]
if !columnPin.Get() && keypad.inputEnabled {
keypad.inputEnabled = false
keypad.lastColumn = columnIndex
keypad.lastRow = rowIndex
return keypad.lastRow, keypad.lastColumn
}
if columnPin.Get() &&
columnIndex == keypad.lastColumn &&
rowIndex == keypad.lastRow &&
!keypad.inputEnabled {
keypad.inputEnabled = true
}
}
rowPin.High()
}
return -1, -1
}
+16 -38
View File
@@ -56,71 +56,49 @@ func (d *Device) Stop() {
d.en.Low()
}
// PWM is the interface necessary for controlling the motor driver.
type PWM interface {
Configure(config machine.PWMConfig) error
Channel(pin machine.Pin) (channel uint8, err error)
Top() uint32
Set(channel uint8, value uint32)
SetPeriod(period uint64) error
}
// PWMDevice is a motor with speed control.
// a1 and a2 are the directional GPIO pins.
// en is the PWM pin that controls the motor speed.
type PWMDevice struct {
a1, a2 machine.Pin
spc uint8
pwm PWM
en machine.PWM
}
// NewWithSpeed returns a new PWMMotor driver that uses an already configured PWM channel
// to control speed.
func NewWithSpeed(direction1, direction2 machine.Pin, spc uint8, pwm PWM) PWMDevice {
// NewWithSpeed returns a new PWMMotor driver that uses a PWM pin to control speed.
func NewWithSpeed(direction1, direction2 machine.Pin, speedPin machine.PWM) PWMDevice {
return PWMDevice{
a1: direction1,
a2: direction2,
spc: spc,
pwm: pwm,
a1: direction1,
a2: direction2,
en: speedPin,
}
}
// Configure configures the PWMDevice. Note that the PWM interface and
// channel must already be configured, this function will not do it for you.
func (d *PWMDevice) Configure() error {
// Configure configures the PWMDevice.
func (d *PWMDevice) Configure() {
d.a1.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.a2.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.en.Configure()
d.Stop()
return nil
}
// Forward turns motor on in forward direction at specific speed as a percentage.
func (d *PWMDevice) Forward(speed uint32) {
if speed > 100 {
speed = 100
}
// Forward turns motor on in forward direction at specific speed.
func (d *PWMDevice) Forward(speed uint16) {
d.a1.High()
d.a2.Low()
d.pwm.Set(d.spc, d.pwm.Top()*speed/100)
d.en.Set(speed)
}
// Backward turns motor on in backward direction at specific speed as a percentage.
func (d *PWMDevice) Backward(speed uint32) {
if speed > 100 {
speed = 100
}
// Backward turns motor on in backward direction at specific speed.
func (d *PWMDevice) Backward(speed uint16) {
d.a1.Low()
d.a2.High()
d.pwm.Set(d.spc, d.pwm.Top()*speed/100)
d.en.Set(speed)
}
// Stop turns motor off.
func (d *PWMDevice) Stop() {
d.a1.Low()
d.a2.Low()
d.pwm.Set(d.spc, 0)
d.en.Set(0)
}
+19 -29
View File
@@ -49,52 +49,42 @@ func (d *Device) Stop() {
d.ib.Low()
}
// PWM is the interface necessary for controlling the motor driver.
type PWM interface {
Configure(config machine.PWMConfig) error
Channel(pin machine.Pin) (channel uint8, err error)
Top() uint32
Set(channel uint8, value uint32)
SetPeriod(period uint64) error
}
// PWMDevice is a motor with speed control.
// ia and ib are the directional/speed PWM pins.
type PWMDevice struct {
pwm PWM
ca, cb uint8
ia, ib machine.PWM
}
// NewWithSpeed returns a new PWMMotor driver that uses 2 PWM pins to control both direction and speed.
func NewWithSpeed(ca, cb uint8, pwm PWM) PWMDevice {
func NewWithSpeed(direction1, direction2 machine.PWM) PWMDevice {
return PWMDevice{
pwm: pwm,
ca: ca,
cb: cb,
ia: direction1,
ib: direction2,
}
}
// Configure configures the PWMDevice. Note that the pins, PWM interface,
// and channels must all already be configured.
func (d *PWMDevice) Configure() (err error) {
// Configure configures the PWMDevice.
func (d *PWMDevice) Configure() {
d.ia.Configure()
d.ib.Configure()
d.Stop()
return
}
// Forward turns motor on in forward direction at specific speed as a percentage.
func (d *PWMDevice) Forward(speed uint32) {
d.pwm.Set(d.ca, d.pwm.Top()*speed/100)
d.pwm.Set(d.cb, 0)
// Forward turns motor on in forward direction at specific speed.
func (d *PWMDevice) Forward(speed uint16) {
d.ia.Set(speed)
d.ib.Set(0)
}
// Backward turns motor on in backward direction at specific speed as a percentage.
func (d *PWMDevice) Backward(speed uint32) {
d.pwm.Set(d.ca, 0)
d.pwm.Set(d.cb, d.pwm.Top()*speed/100)
// Backward turns motor on in backward direction at specific speed.
func (d *PWMDevice) Backward(speed uint16) {
d.ia.Set(0)
d.ib.Set(speed)
}
// Stop turns motor off.
func (d *PWMDevice) Stop() {
d.pwm.Set(d.ca, 0)
d.pwm.Set(d.cb, 0)
d.ia.Set(0)
d.ib.Set(0)
}
+2 -2
View File
@@ -18,13 +18,13 @@ func TestWhoAmI(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice(c, ADDRESS)
copy(fake.Registers[:], defaultRegisters())
fake.SetupRegisters(defaultRegisters())
bus.AddDevice(fake)
dev := New(bus)
c.Assert(dev.Connected(), qt.Equals, true)
fake.Registers[WHO_AM_I] = 0x99
fake.SetupRegister(WHO_AM_I, 0x99)
c.Assert(dev.Connected(), qt.Equals, false)
}
-85
View File
@@ -1,85 +0,0 @@
// Driver works for max7219 and 7221
// Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf
package max72xx
import (
"machine"
)
type Device struct {
bus machine.SPI
cs machine.Pin
}
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
// The SPI frequency must not be higher than 10MHz.
// parameter cs: the datasheet also refers to this pin as "load" pin.
func NewDevice(bus machine.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs,
}
}
// Configure setups the pins.
func (driver *Device) Configure() {
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
driver.cs.Configure(outPutConfig)
}
// SetScanLimit sets the scan limit. Maximum is 8.
// Example: a 4 digit 7SegmentDisplay has a scan limit of 4
func (driver *Device) SetScanLimit(digitNumber uint8) {
driver.WriteCommand(byte(REG_SCANLIMIT), byte(digitNumber-1))
}
// SetDecodeMode sets the decode mode for 7 segment displays.
// digitNumber = 1 -> 1 digit gets decoded
// digitNumber = 2 or 3, or 4 -> 4 digit are being decoded
// digitNumber = 8 -> 8 digits are being decoded
// digitNumber 0 || digitNumber > 8 -> no decoding is being used
func (driver *Device) SetDecodeMode(digitNumber uint8) {
switch digitNumber {
case 1: // only decode first digit
driver.WriteCommand(REG_DECODE_MODE, 0x01)
case 2, 3, 4: // decode digits 3-0
driver.WriteCommand(REG_DECODE_MODE, 0x0F)
case 8: // decode 8 digits
driver.WriteCommand(REG_DECODE_MODE, 0xFF)
default:
driver.WriteCommand(REG_DECODE_MODE, 0x00)
}
}
// StartShutdownMode sets the IC into a low power shutdown mode.
func (driver *Device) StartShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x00)
}
// StartShutdownMode sets the IC into normal operation mode.
func (driver *Device) StopShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x01)
}
// StartDisplayTest starts a display test.
func (driver *Device) StartDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x01)
}
// StopDisplayTest stops the display test and gets into normal operation mode.
func (driver *Device) StopDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x00)
}
func (driver *Device) writeByte(data byte) {
driver.bus.Transfer(data)
}
// WriteCommand write data to a given register.
func (driver *Device) WriteCommand(register, data byte) {
driver.cs.Low()
driver.writeByte(register)
driver.writeByte(data)
driver.cs.High()
}
-18
View File
@@ -1,18 +0,0 @@
package max72xx
const (
REG_NOOP byte = 0x00
REG_DIGIT0 byte = 0x01
REG_DIGIT1 byte = 0x02
REG_DIGIT2 byte = 0x03
REG_DIGIT3 byte = 0x04
REG_DIGIT4 byte = 0x05
REG_DIGIT5 byte = 0x06
REG_DIGIT6 byte = 0x07
REG_DIGIT7 byte = 0x08
REG_DECODE_MODE byte = 0x09 // turn of for led matrix, turn on for digits
REG_INTENSITY byte = 0x0A
REG_SCANLIMIT byte = 0x0B
REG_SHUTDOWN byte = 0x0C // turn on for no shutdown mode
REG_DISPLAY_TEST byte = 0x0F // turn off for no display test
)

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