Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions examples/neopixel/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Demonstrates NeoPixel (WS2812B) RGB LED control.
//
// Tested on Waveshare RP2350-LCD-1.47 with onboard RGB LED on GP22.
//
// To flash:
//
// tinygo flash -target=pico2 ./examples/neopixel/
package main

import (
"image/color"
"machine"
"time"

"tinygo.org/x/drivers/neopixel"
)

func main() {
pixel, err := neopixel.New(machine.GP22, 1)
if err != nil {
panic(err)
}
pixel.SetBrightness(50)

colors := []color.RGBA{
{R: 255, G: 0, B: 0},
{R: 0, G: 255, B: 0},
{R: 0, G: 0, B: 255},
}

for i := 0; ; i = (i + 1) % 3 {
pixel.SetPixel(0, colors[i])
pixel.Show()
time.Sleep(time.Second)
}
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
module tinygo.org/x/drivers


go 1.22.1

toolchain go1.23.1


require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/frankban/quicktest v1.10.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/orsinium-labs/tinymath v1.1.0
github.com/soypat/natiu-mqtt v0.5.1
github.com/tinygo-org/pio v0.3.0
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
golang.org/x/net v0.33.0
tinygo.org/x/tinyfont v0.3.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ github.com/orsinium-labs/tinymath v1.1.0 h1:KomdsyLHB7vE3f1nRAJF2dyf1m/gnM2HxfTe
github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A=
github.com/soypat/natiu-mqtt v0.5.1 h1:rwaDmlvjzD2+3MCOjMZc4QEkDkNwDzbct2TJbpz+TPc=
github.com/soypat/natiu-mqtt v0.5.1/go.mod h1:xEta+cwop9izVCW7xOx2W+ct9PRMqr0gNVkvBPnQTc4=
github.com/tinygo-org/pio v0.3.0 h1:opEnOtw58KGB4RJD3/n/Rd0/djYGX3DeJiXLI6y/yDI=
github.com/tinygo-org/pio v0.3.0/go.mod h1:wf6c6lKZp+pQOzKKcpzchmRuhiMc27ABRuo7KVnaMFU=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
Expand Down
80 changes: 80 additions & 0 deletions neopixel/neopixel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Package neopixel implements a driver for WS2812B/NeoPixel RGB LED strips.
//
// On RP2040/RP2350, it uses PIO for hardware-timed control.
// On other platforms, it falls back to the ws2812 bit-bang driver.
package neopixel // import "tinygo.org/x/drivers/neopixel"

import (
"image/color"
"machine"
)

// Device controls a strip of WS2812B/NeoPixel LEDs.
type Device struct {
pin machine.Pin
pixels []color.RGBA
brightness uint8
backend backend
}

// backend is the platform-specific implementation for sending pixel data.
type backend interface {
init(pin machine.Pin) error
writePixels(pixels []color.RGBA, brightness uint8) error
}

// New creates a new NeoPixel device on the given pin with the specified number of pixels.
func New(pin machine.Pin, numPixels int) (*Device, error) {
d := &Device{
pin: pin,
pixels: make([]color.RGBA, numPixels),
brightness: 255,
backend: newBackend(),
}
if err := d.backend.init(pin); err != nil {
return nil, err
}
return d, nil
}

// SetPixel sets the color of pixel at index i.
func (d *Device) SetPixel(i int, c color.RGBA) {
if i >= 0 && i < len(d.pixels) {
d.pixels[i] = c
}
}

// Show sends the current pixel buffer to the LED strip.
func (d *Device) Show() error {
return d.backend.writePixels(d.pixels, d.brightness)
}

// SetBrightness sets the global brightness (0-255).
func (d *Device) SetBrightness(b uint8) {
d.brightness = b
}

// Fill sets all pixels to the given color.
func (d *Device) Fill(c color.RGBA) {
for i := range d.pixels {
d.pixels[i] = c
}
}

// Clear turns off all pixels.
func (d *Device) Clear() {
d.Fill(color.RGBA{})
}

// NumPixels returns the number of pixels in the strip.
func (d *Device) NumPixels() int {
return len(d.pixels)
}

// applyBrightness scales a color by the brightness value.
func applyBrightness(c color.RGBA, brightness uint8) (r, g, b uint8) {
r = uint8((uint16(c.R) * uint16(brightness)) >> 8)
g = uint8((uint16(c.G) * uint16(brightness)) >> 8)
b = uint8((uint16(c.B) * uint16(brightness)) >> 8)
return
}
33 changes: 33 additions & 0 deletions neopixel/neopixel_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//go:build !rp2040 && !rp2350

package neopixel

import (
"image/color"
"machine"

"tinygo.org/x/drivers/ws2812"
)

type otherBackend struct {
ws ws2812.Device
}

func newBackend() backend {
return &otherBackend{}
}

func (b *otherBackend) init(pin machine.Pin) error {
pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
b.ws = ws2812.NewWS2812(pin)
return nil
}

func (b *otherBackend) writePixels(pixels []color.RGBA, brightness uint8) error {
adjusted := make([]color.RGBA, len(pixels))
for i, c := range pixels {
r, g, bl := applyBrightness(c, brightness)
adjusted[i] = color.RGBA{R: r, G: g, B: bl}
}
return b.ws.WriteColors(adjusted)
}
40 changes: 40 additions & 0 deletions neopixel/neopixel_rp2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build rp2040 || rp2350

package neopixel

import (
"image/color"
"machine"

pio "github.com/tinygo-org/pio/rp2-pio"
"github.com/tinygo-org/pio/rp2-pio/piolib"
)

type rp2Backend struct {
ws *piolib.WS2812B
}

func newBackend() backend {
return &rp2Backend{}
}

func (b *rp2Backend) init(pin machine.Pin) error {
sm, err := pio.PIO0.ClaimStateMachine()
if err != nil {
return err
}
ws, err := piolib.NewWS2812B(sm, pin)
if err != nil {
return err
}
b.ws = ws
return nil
}

func (b *rp2Backend) writePixels(pixels []color.RGBA, brightness uint8) error {
for _, c := range pixels {
r, g, bl := applyBrightness(c, brightness)
b.ws.PutRGB(r, g, bl)
}
return nil
}