Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First write to WS2812 Led 0 sets green to 0xff (seen on RP2040 boards) #4251

Open
andrewfstratton opened this issue Apr 29, 2024 · 12 comments
Open
Labels
question Question about usage of TinyGo

Comments

@andrewfstratton
Copy link

I cannot get the WS2812 leds to be set correctly immediately following a reset - e.g. the code below should switch all the leds off.

The code is a cut down version of the problem, which can be run on Waveshare RP2040 Zero and One - the Zero shows a green led and the one shows a red led (other leds do not appear to be lit).

package main

import (
	"image/color"
	"machine"

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

const GPIO_PIN = machine.GPIO16 // GPIO18 for RP2040 3 Key Keyboard

func main() {
	var led ws2812.Device
	led = ws2812.NewWS2812(GPIO_PIN)
	led.Pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	var Off = color.RGBA{R: 0x00, G: 0x00, B: 0x00}
	var colours [1]color.RGBA
	for id := range colours {
		colours[id] = Off
	}
	led.WriteColors(colours[:])
}

There is some delay needed before leds can be set. I have similar issues with the Waveshare RP2400 3 Key keyboard - and have put a delay in to fix (hack) the problem - please see https://github.com/andrewfstratton/rp3keys/tree/d834fcf139aed9b9c6121a47644f0b21a8ff2d0e
With this delay, the red led does briefly come on, but is then reset - it seems that setting the leds before this delay will set them incorrectly.

@andrewfstratton
Copy link
Author

Note: This isn't about resetting the leds (since they are reset on powerup) but about being able to change them immediately after power on.

Copy link
Member

aykevl commented Apr 29, 2024

How much delay do you need here to fix the problem?
I can think of two possible reasons why this happens:

  1. If the power comes up at the same time, it may be that the LEDs need a bit of time to fully start up.
  2. It may be that the pin is not read as "low" before initialization leading to the first bit to be read incorrectly.

I'm not sure what a correct fix would be: this sounds like a problem that depends on the exact system so I'm hesitant to put in a delay without understanding the problem.

Also, usually these LEDs start up black? I've seen exceptions but most of them are black when powering on.

@andrewfstratton
Copy link
Author

How much delay do you need here to fix the problem?

The delay was for me to bodge it by resetting the leds after they have been switched on in error

I have a version of the code below that may help - it switches the leds on and off. I then recorded the result on resetting it several times using the Waveshare RP2040 Zero (not the keyboard):

  • Green (initial flash)
  • 5 x Green, 1 x Blue
  • 3 Green, 1 Blue
  • 7 Green, 1 Blue
  • 6 Green, 1 Off (black) CORRECT?!
package main

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

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

const GPIO_PIN = machine.GPIO16

func main() {
	var led ws2812.Device
	led = ws2812.NewWS2812(GPIO_PIN)
	led.Pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	var Off = color.RGBA{R: 0x00, G: 0x00, B: 0x00}
	var On = color.RGBA{R: 0x1f, G: 0x1f, B: 0x1f}
	var colours [1]color.RGBA
	time.Sleep(time.Millisecond * 1000)
	for {
		for id := range colours {
			colours[id] = Off
		}
		led.WriteColors(colours[:])
		time.Sleep(time.Millisecond * 500)
		for id := range colours {
			colours[id] = On
		}
		led.WriteColors(colours[:])
		time.Sleep(time.Millisecond * 500)
	}
}

I then swapped the On and Off round and recorded the resets (i.e. On first then Off):

  • 14 Green, then 1 Yellow (?!)

I then removed the first 1 second delay and ran again:

  • 4 Green, Yellow
  • 4 Green, yellow
  • Green, 2 Yellow
  • Green yellow
  • Green

And then swapped back to Off then On (with no initial delay):

  • 2 Green, 1 Black
  • 6 Green, Black,
  • 3 Green, 2Black
  • Green, Black
  1. If the power comes up at the same time, it may be that the LEDs need a bit of time to fully start up.

I tried a plain 1 second delay at the beginning of main - still incorrect led lit after startup beginning

  1. It may be that the pin is not read as "low" before initialization leading to the first bit to be read incorrectly.

I also tried a delay after configuring the Pin before write the leds - no joy - maybe the initialisation is incorrectly starting comms with the leds?

Also, usually these LEDs start up black? I've seen exceptions but most of them are black when powering on.

I know - so strange they are green/yellow/red more often than black. They are black if I don't access them?!

@andrewfstratton
Copy link
Author

Another experiment:

Here's the code this time there's a half second delay before setting the leds Off. The result is that many resets show Green (then go off), less often the leds are off.

package main

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

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

const GPIO_PIN = machine.GPIO16

func main() {
	var led ws2812.Device
	led = ws2812.NewWS2812(GPIO_PIN)
	led.Pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	time.Sleep(time.Millisecond * 500)
	var Off = color.RGBA{R: 0x00, G: 0x00, B: 0x00}
	var colours [1]color.RGBA
	for {
		for id := range colours {
			colours[id] = Off
		}
		led.WriteColors(colours[:])
		time.Sleep(time.Millisecond * 500)
	}
}

However, if second delay is removed, then the behaviour changes:

led.WriteColors(colours[:])
// time.Sleep(time.Millisecond * 500)

Now, resets get Green - and STAY GREEN, most of the time, sometimes they are black.

This looks to me like the led write can't cope with the traffic...

@andrewfstratton andrewfstratton changed the title RGB Led setting startup delay needed RGB Led setting startup incorrect Apr 30, 2024
@andrewfstratton andrewfstratton changed the title RGB Led setting startup incorrect RGB Led startup incorrectly lit Apr 30, 2024
@deadprogram
Copy link
Member

At least from what I can tell, this is something related to your specific hardware @andrewfstratton not TinyGo itself. Or perhaps related to the ws2812 driver implementation in https://github.com/tinygo-org/drivers/tree/release/ws2812

@deadprogram deadprogram added the question Question about usage of TinyGo label May 1, 2024
@andrewfstratton
Copy link
Author

So I tried this with a Cytron Maker Pi RP2040 which has 2 RGB Leds - this is my last RP2040 with WS2812 Leds - so I don't have any other boards I can try...it would be good to see if other boards get this behaviour since I suspect this is not board or manufacturer specific (though I have only tried two manufacturers) and may therefore be the (WS2812) library...

There appear to be two issues here and therefore this issue may need splitting:

Issue 1 : After a reset, the first write to leds, sets led 0 to green incorrectly
Issue 2 : If the leds are set using writeColours without a delay, then requests can fail, possibly due to being continually overwritten/re-requested

Please see the code further down...

I get the following behaviour:

  1. after flash or reset : led 0 is green consistently and led 1 is pink - neither change
  2. after power off then on, both leds are off

If I uncomment the delay (b) sleep code, then:

  1. after flash or reset: at start, led 0 is green and led 1 is pink, then both toggle between off and pink. The first write to led 0 is being ignored
  2. after power on, the same behaviour is seen - i.e. led 0 is green initially
package main

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

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

const GPIO_PIN = machine.GPIO18

var Off = color.RGBA{R: 0x00, G: 0x00, B: 0x00}
var On = color.RGBA{R: 0x3f, G: 0x00, B: 0x1f}

func main() {
	led_pin := GPIO_PIN
	led_pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	// delay A
	time.Sleep(time.Millisecond * 500)
	var led ws2812.Device = ws2812.NewWS2812(led_pin)
	var colours [2]color.RGBA
	for {
		// (b) delay
		// time.Sleep(time.Millisecond * 500)
		for id := range colours {
			colours[id] = On
		}
		led.WriteColors(colours[:])
		// (b) delay
		// time.Sleep(time.Millisecond * 501)
		for id := range colours {
			colours[id] = Off
		}
		led.WriteColors(colours[:])
	}
}

@andrewfstratton
Copy link
Author

I've discovered that the first WS2812 write after power off or reset writes green as 0xff (or a high value - it's hard to be sure) to led 0 instead of the green value given - red and blue values are still set.

e.g. in the code below - both led 0 and led 1 should show blue after reset, but led 0 show turquoise and led 1 shows blue.

Note: I didn't use 0xff to protect my eyes

package main

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

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

const GPIO_PIN = machine.GPIO18

var Off = color.RGBA{R: 0x00, G: 0x00, B: 0x00}
var Pink = color.RGBA{R: 0x3f, G: 0x00, B: 0x1f}
var Blue = color.RGBA{R: 0x00, G: 0x00, B: 0x3f}

func main() {
	led_pin := GPIO_PIN
	led_pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	// delay A
	time.Sleep(time.Millisecond * 500)
	var led ws2812.Device = ws2812.NewWS2812(led_pin)
	var colours [2]color.RGBA
	colours[0] = Blue
	colours[1] = Blue
	led.WriteColors(colours[:])
	for {
		// (b) delay
		time.Sleep(time.Millisecond * 500)
		for id := range colours {
			colours[id] = Pink
		}
		led.WriteColors(colours[:])
		// (b) delay
		time.Sleep(time.Millisecond * 500)
		for id := range colours {
			colours[id] = Off
		}
		led.WriteColors(colours[:])
	}
}

@andrewfstratton andrewfstratton changed the title RGB Led startup incorrectly lit First write to WS2812 Led 0 sets green to 0xff (seen on RP2040 boards) May 3, 2024
@aykevl
Copy link
Member

aykevl commented May 3, 2024

This sounds like you have something wrong with your wiring.
A few things to check:

  • Is the ground of the WS2812 strip connected to the ground of the RP2040 board?
  • Do the LEDs have a good enough power supply?
  • Is the data wire connected well enough? It shouldn't be too long (more than 1m or so can lead to problems).
  • Are you sure you've connected to the right pin on the board?

See https://learn.adafruit.com/adafruit-neopixel-uberguide/basic-connections for a more extensive guide.

I'm running a bunch of WS2812 LEDs every night in a project of mine, and they're powered using a rp2040. So that combination most certainly works for me.

@andrewfstratton
Copy link
Author

andrewfstratton commented May 3, 2024

These are all onboard rgb leds - 4 different board types with two different manufacturers.

Power might be an issue but seems unlikely with one RGB led and the issue occurring on reset and power on - and the arduino C code works fine...

Please could you try my last listing and see what happens?

@Gustavomurta
Copy link

Gustavomurta commented May 6, 2024

I didn't read all the topics.
I'm sending this link, but I don't know if it has anything to do with the problem.
tinygo-org/pio#5

@aykevl
Copy link
Member

aykevl commented May 13, 2024

Did a quick test and I can confirm that the first write results in some weird colors. Subsequent writes work fine however.

This will need a bit more investigation to see what's going on. But a workaround would be something like this for the first write:

        led.WriteColors(colours[:])
        time.Sleep(time.Millisecond * 20)
        led.WriteColors(colours[:])

@aykevl
Copy link
Member

aykevl commented May 13, 2024

My best guess would be that the first time the code runs, not all the code has been loaded into the flash cache, slowing down the assembly and messing up the timing of the signal.

I'm not sure what the best way would be to fix that. One solution would be to place the code in RAM, thereby taking up precious RAM (though not so precious on the rp2040). Another solution would be some sort of prefetch, but unfortunately the rp2040 doesn't support that. The easiest solution would probably to send data of a single pixel (or even a single byte), sleep for ~10ms, and then send the real data. Like this:

        led.Write([]byte{0x00})
        time.Sleep(time.Millisecond * 10)
        led.WriteColors(colours[:])

(This might still result in a flash sometimes and I'm not sure we should add this to the ws2812 driver because it's chip-specific).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Question about usage of TinyGo
Projects
None yet
Development

No branches or pull requests

4 participants