Compare commits

...

7 Commits

Author SHA1 Message Date
soypat 5c305f9b6f ssd1306: fix thumby function arguments 2025-07-02 11:16:40 -03:00
soypat 1e4110b5a2 add thumby case to smoke tests 2025-07-02 11:05:47 -03:00
soypat e286861661 fix smoke tests 2025-07-02 11:05:07 -03:00
soypat 589bf19b01 fix bug 2025-07-02 10:51:29 -03:00
soypat ff4d15cea9 this is what I meant 2025-07-02 10:44:06 -03:00
JP Hastings-Spital d02d21ecea feat: allow gps init with address
Adafruit's Mini GPS PA1010D Module works with this device driver, but requires 0x10 as the address, rather than 0x42.

This change allows the device to be initialised with whatever i2c address is needed, while maintaining backward compatibility.

Adds new constants to allow easy configuration of both the ublox device and the PA1010D.
2025-06-30 14:00:55 +02:00
Yurii Soldak 805e2a02f8 lsm6ds3tr: avoid unnecessary heap allocations (#766)
* lsm6ds3tr: avoid unnecessary heap allocations
* lsm6ds3tr: use helper functions, for readability
* lsm6ds3tr: return slice of the internal buffer on readBytes
2025-06-25 10:03:41 +02:00
11 changed files with 116 additions and 204 deletions
+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.NewI2CWithAddress(machine.I2C0, gps.UBLOX_I2C_ADDRESS)
parser := gps.NewParser()
var fix gps.Fix
for {
-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,8 +1,6 @@
package main
import (
"machine"
"image/color"
"time"
@@ -10,21 +8,21 @@ import (
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_400KHZ,
})
display := ssd1306.NewI2C(machine.I2C0)
display.Configure(ssd1306.Config{
Address: ssd1306.Address_128_32,
Width: 128,
Height: 32,
})
// Thumby will have preset size.
// If not compiling for thumby the width and height will be whatever we suggest
const suggestHeight = 32
const suggestWidth = 128
var display *ssd1306.Device
var err error
display, err = makeSSD1306(suggestWidth, suggestHeight)
if err != nil {
panic(err)
}
display.ClearDisplay()
x := int16(0)
y := int16(0)
width, height := display.Size()
x := int16(width)
y := int16(height)
deltaX := int16(1)
deltaY := int16(1)
for {
@@ -39,11 +37,11 @@ func main() {
x += deltaX
y += deltaY
if x == 0 || x == 127 {
if x == 0 || x == width-1 {
deltaX = -deltaX
}
if y == 0 || y == 31 {
if y == 0 || y == height-1 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
+29
View File
@@ -0,0 +1,29 @@
//go:build !thumby
package main
import (
"machine"
"tinygo.org/x/drivers/ssd1306"
)
func makeSSD1306(width, height int16) (*ssd1306.Device, error) {
err := machine.I2C0.Configure(machine.I2CConfig{
Frequency: 400 * machine.KHz,
})
if err != nil {
return nil, err
}
address := uint16(ssd1306.Address)
if width == 128 && (height == 32 || height == 64) {
address = ssd1306.Address_128_32
}
display := ssd1306.NewI2C(machine.I2C0)
display.Configure(ssd1306.Config{
Address: address,
Width: width,
Height: height,
})
return &display, nil
}
+22
View File
@@ -0,0 +1,22 @@
//go:build thumby
package main
import (
"machine"
"tinygo.org/x/drivers/ssd1306"
)
func makeSSD1306(_, _ int16) (*ssd1306.Device, error) {
// width and height are known for thumby.
machine.SPI0.Configure(machine.SPIConfig{})
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
display.Configure(ssd1306.Config{
Width: 72,
Height: 40,
ResetCol: ssd1306.ResetValue{28, 99},
ResetPage: ssd1306.ResetValue{0, 5},
})
return &display, nil
}
-48
View File
@@ -1,48 +0,0 @@
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 8000000,
})
display := ssd1306.NewSPI(machine.SPI0, machine.P8, machine.P7, machine.P9)
display.Configure(ssd1306.Config{
Width: 128,
Height: 64,
})
display.ClearDisplay()
x := int16(64)
y := int16(32)
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)
}
}
-50
View File
@@ -1,50 +0,0 @@
// This example using the SSD1306 OLED display over SPI on the Thumby board
// A very tiny 72x40 display.
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.SPI0.Configure(machine.SPIConfig{})
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
display.Configure(ssd1306.Config{
Width: 72,
Height: 40,
ResetCol: ssd1306.ResetValue{28, 99},
ResetPage: ssd1306.ResetValue{0, 5},
})
display.ClearDisplay()
x := int16(36)
y := int16(20)
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 == 71 {
deltaX = -deltaX
}
if y == 0 || y == 39 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
+7 -1
View File
@@ -69,10 +69,16 @@ func NewUART(uart drivers.UART) Device {
}
// NewI2C creates a new I2C GPS connection.
// Uses the default i2c address (0x42) for backward compatibility reasons.
func NewI2C(bus drivers.I2C) Device {
return NewI2CWithAddress(bus, I2C_ADDRESS)
}
// NewI2CWithAddress creates a new I2C GPS connection on the provided address
func NewI2CWithAddress(bus drivers.I2C, i2cAddress uint16) Device {
return Device{
bus: bus,
address: I2C_ADDRESS,
address: i2cAddress,
buffer: make([]byte, bufferSize),
bufIdx: bufferSize,
sentence: strings.Builder{},
+5 -1
View File
@@ -4,7 +4,11 @@ package gps
// The I2C address which this device listens to.
const (
I2C_ADDRESS = 0x42
// To ensure backward compatibility
I2C_ADDRESS = UBLOX_I2C_ADDRESS
UBLOX_I2C_ADDRESS = 0x42
PA1010D_I2C_ADDRESS = 0x10
)
const (
+35 -24
View File
@@ -8,7 +8,6 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -26,7 +25,7 @@ type Device struct {
accelSampleRate AccelSampleRate
gyroRange GyroRange
gyroSampleRate GyroSampleRate
buf [6]uint8
buf [7]uint8 // up to 6 bytes for read + 1 byte for the register address
}
// Configuration for LSM6DS3TR device.
@@ -84,30 +83,20 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
d.gyroSampleRate = GYRO_SR_104
}
data := d.buf[:1]
// Configure accelerometer
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
err = d.writeByte(CTRL1_XL, uint8(d.accelRange)|uint8(d.accelSampleRate))
if err != nil {
return
}
// Set ODR bit
err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
// Enable ODR scaling
err = d.setBits(CTRL4_C, BW_SCAL_ODR_ENABLED)
if err != nil {
return
}
// Configure gyroscope
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
err = d.writeByte(CTRL2_G, uint8(d.gyroRange)|uint8(d.gyroSampleRate))
if err != nil {
return
}
@@ -118,8 +107,10 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Connected returns whether a LSM6DS3TR has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data := d.buf[:1]
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
data, err := d.readBytes(WHO_AM_I, 1)
if err != nil {
return false
}
return data[0] == 0x6A
}
@@ -128,8 +119,7 @@ func (d *Device) Connected() bool {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_XL, data)
data, err := d.readBytes(OUTX_L_XL, 6)
if err != nil {
return
}
@@ -153,8 +143,7 @@ func (d *Device) ReadAcceleration() (x, y, 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 *Device) ReadRotation() (x, y, z int32, err error) {
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
data, err := d.readBytes(OUTX_L_G, 6)
if err != nil {
return
}
@@ -177,8 +166,7 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data := d.buf[:2]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
data, err := d.readBytes(OUT_TEMP_L, 2)
if err != nil {
return
}
@@ -187,3 +175,26 @@ func (d *Device) ReadTemperature() (t int32, err error) {
t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
return
}
func (d *Device) readBytes(reg, size uint8) ([]byte, error) {
d.buf[0] = reg
err := d.bus.Tx(d.Address, d.buf[0:1], d.buf[1:size+1])
if err != nil {
return nil, err
}
return d.buf[1 : size+1], nil
}
func (d *Device) writeByte(reg, value uint8) error {
d.buf[0] = reg
d.buf[1] = value
return d.bus.Tx(d.Address, d.buf[0:2], nil)
}
func (d *Device) setBits(reg, bits uint8) error {
data, err := d.readBytes(reg, 1)
if err != nil {
return err
}
return d.writeByte(reg, (data[0]&^bits)|bits)
}
+2 -2
View File
@@ -65,8 +65,8 @@ tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht4x/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/
tinygo build -size short -o ./build/test.hex -target=thumby ./examples/ssd1306/
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go