Open maloo opened 2 years ago
Thanks for logging the issue @maloo. We have been getting some reports lately about the colors on this driver, and I believe @Ellerbach was going to take a look to see what was happening. @Ellerbach can you please also take a look at this one?
Could this be related to https://github.com/dotnet/iot/issues/1328?
The color issues with the WS2812B have always existed, so I considered making a new version of the driver #1761. But because of the problem of how to define the pixel color format, this PR has been on hold. If you're in a hurry to solve this issue, consider using my code to solve the problem for the time being.
The specialized formats of neo via SPi will never be supported by major Gfx libs like image sharp. So you will always need a conversion step from these to the neo native formats. A span of bytes is probably the best common layer between apis as this can be created from native and dotnet memory of all sorts. If you render in for example ImageSharp 24bit and then add a conversion to BitmapImage you probably solve your rendering. As for the Neo3 format, that might need to be updated to support Pi4s where there is a delay in between bytes. Do you know if the same delay exists in Pi2B etc? I have been using this driver for long time on Pi3B+ without issue (at fixed 250MHz core clock) and now with the above fix on Pi4B. I've used 1x and 8x Neo.
[Triage] nano framework might have a fix for this. @Ellerbach to provide more info
Let me know if you want the fix I described above. It is used in production on both Pi3B+ and Pi4B+. But if there is a way to get rid of the delay between bytes, that would be better.
[Triage] Hey @maloo, sorry for late response, if your offer is still valid we'd be happy to take a fix 😄
I'm a bit busy at the moment, can I just upload the file here? Or post the relevant part of the code?
Sure, if you think you know how to fix it, we're happy for anything you can provide.
Can't seem to find the updated driver file, but I found some code I use on RaspPi 4s.
TL;DR Align data so each bit (hi-lo) is sent as 3 bits, assume an implicit 0 between each byte (the delay between bytes in Pi4), so 100 = 0, 110 = 1, then add 00 at the end to pad.
Half bright colors (0b0111_1111 => 0b100_110_11, 0b110_110_11, 0b110_110_00)
var red = new byte[] {
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
};
var green = new byte[] {
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
};
var blue = new byte[] {
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
};
var cyan = new byte[] {
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
};
var magenta = new byte[] {
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
};
var black = new byte[] {
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
};
var yellow = new byte[] {
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_110_11, 0b110_110_11, 0b110_110_00,
0b100_100_10, 0b100_100_10, 0b100_100_00,
};
SpiConnectionSettings settings = new(0, 0) {
ClockFrequency = 2_400_000,
Mode = SpiMode.Mode0,
DataBitLength = 8
};
using SpiDevice spi = SpiDevice.Create(settings);
spi.Write(black);
Describe the bug
Colors are not what they should on Raspberry Pi 4.
It seems Raspberry Pi 4 (more?) introduce a one (1.5?) cycle delay between bytes. This mess up the timing of BitmapNeo3 format that send SPI 3bits per Neo pixel bit. 0b110 for one and 0b100 for zero. So when sending Red:
the 3rd and 6th triplet gets split over a byte boundary. The 0b110 become 0b1x10 and the x-delay is sent as 0, so we get 0b1010 instead of 0b110. This is out of spec and most likely interpreted by Neo as one or two 0s instead of a 1.
A workaround is to utilize the inter byte delay as a hardcoded 0 and for example send the following to get red:
I'm not sure if the driver in Linux can be tweeked to skip the inter byte delay. There is a .pad in the ioctl struct, but I'm not sure if the kernel driver use it. It does not seem like dotnet IoT use it which should mean it is set to 0. I have not tested any other HW, just the Raspberry Pi 4B
Steps to reproduce
Run WS2812b sample and hardcode color to red.
Expected behavior
Red color on Nep pixel
Actual behavior
Orangish color on No pixel
Versions used
dotnet 6 - but probably irrelevant.