zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.66k stars 6.52k forks source link

drivers: led_strip: WS2812 driver broken on SPI0, SPI1 and SPI2 on the nRF52840 #57147

Closed Klievan closed 1 year ago

Klievan commented 1 year ago

Describe the bug The WS2812 driver used to drive neo-pixels, led-strips and the like seems to have broken on the nRF52840, possibly on other nRF52-series SoC's as well. When using SPI3 (which only is a SPI-master peripheral) the issue seems to go away. This seems to be a regression as I've had the LED sample running on a nRF52840 DK before, but I don't have a specific version.

To Reproduce Steps to reproduce the behavior:

  1. Grab a nRF52840 devkit (I don't think you need to have a WS2812 led connected, looking at the error) and follow the overlay instructions on the led_ws2812 sample. Make sure you use the SPIM driver and select SPI 0 - 1.
  2. Observe that upon boot the following message is printed: spi_nrfx_spim: Timeout waiting for transfer complete. Also the error main: couldn't update strip: -5 will be spammed.
  3. Switch the led over to SPI3, rebuild and observe no errors printed. If you have a LED-strip connected it should now be flashing.

Expected behavior The driver to work on all SPI peripherals.

Impact For us the impact was minimal as our SPI3 peripheral was free. For people not having a free SPI3 peripheral they might have to look at the I2C driver.

Logs and console output

- - - - - - - - - - - - - - - - - TARGET RESET - - - - - - - - - - - - - - - - -
*** Booting Zephyr OS build v3.2.99-ncs2-5-g2ec53916acba ***
[00:00:01.928,070] \033[0m<inf> main: Found LED strip device ws2812@0\033[0m
[00:00:01.928,070] \033[0m<inf> main: Displaying pattern on strip\033[0m
[00:00:02.128,204] \033[1;31m<err> spi_nrfx_spim: Timeout waiting for transfer complete\033[0m
[00:00:02.128,356] \033[1;31m<err> main: couldn't update strip: -116\033[0m
[00:00:02.178,588] \033[1;31m<err> main: couldn't update strip: -5\033[0m
[00:00:02.228,820] \033[1;31m<err> main: couldn't update strip: -5\033[0m

Environment (please complete the following information):

xudongzheng commented 1 year ago

I along with ZMK (zmkfirmware/zmk#1746) ran into a similar issue. A few observations:

Klievan commented 1 year ago

It seems to work when pinctrl for SPI0/SPI1/SPI2 have NRF_PSEL(SPIM_SCK, ...) defined with an unused pin as a placeholder. SPI3 works both with and without SPIM_SCK defined.

Might be interesting to drop my pinctrl definition in that case

    spi0_default: spi0_default {
        group1 {
            psels = <NRF_PSEL_DISCONNECTED(SPIM_SCK)>,
                    <NRF_PSEL(SPIM_MOSI, 0, 16)>,
                    <NRF_PSEL_DISCONNECTED(SPIM_MISO)>;
        };
    };

    spi0_sleep: spi0_sleep {
        group1 {
            psels = <NRF_PSEL_DISCONNECTED(SPIM_SCK)>,
                    <NRF_PSEL(SPIM_MOSI, 0, 16)>,
                    <NRF_PSEL_DISCONNECTED(SPIM_MISO)>;
            low-power-enable;
        };
    };
abelbmx commented 1 year ago

I have a problem with the firmware that I had for ZMK Corne with this change in a nice!nano v2. When I was with SPI1 I never had problems with the nice!nano, but with SPI3 the nicenano out of nowhere stops receiving keystrokes even though it is connected correctly, so I can't write. If I load a firmware with SPI1 the problem disappears. Anyone else has happened? Tried with 3 nice!nano and the problem is the same.

trlongth commented 1 year ago

I have this problem. I can only build with SPI3 but after flashing, only 10 leds work even though I specified 32.

zpm1066 commented 1 year ago

On a particle_xenon, the following works with SPI0. I' using a 8 led strip.

&spi0 {
    compatible = "nordic,nrf-spi";
    status = "okay";
    pinctrl-0 = <&spi0_default>;
    pinctrl-1 = <&spi0_sleep>;
    cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; /* D4 */ 
        pinctrl-names = "default", "sleep";

    led_strip: ws2812@0 {
        compatible = "worldsemi,ws2812-spi";

        /* SPI */
        reg = <0>; /* ignored, but necessary for SPI bindings */
        spi-max-frequency = <SPI_FREQ>;

        /* WS2812 */
        chain-length = <8>; /* arbitrary; change at will */
        color-mapping = <LED_COLOR_ID_GREEN
                 LED_COLOR_ID_RED
                 LED_COLOR_ID_BLUE>;
        spi-one-frame = <ONE_FRAME>;
        spi-zero-frame = <ZERO_FRAME>;
    };
};

&pinctrl {
    spi0_default: spi0_default {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 47)>,
                <NRF_PSEL(SPIM_MOSI, 0, 45)>,
                <NRF_PSEL(SPIM_MISO, 0, 46)>;
        };
    };

    spi0_sleep: spi0_sleep {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 47)>,
                <NRF_PSEL(SPIM_MOSI, 0, 45)>,
                <NRF_PSEL(SPIM_MISO, 0, 46)>;
            low-power-enable;
        };
    };
};
anangl commented 1 year ago

Describe the bug The WS2812 driver used to drive neo-pixels, led-strips and the like seems to have broken on the nRF52840, possibly on other nRF52-series SoC's as well. When using SPI3 (which only is a SPI-master peripheral) the issue seems to go away. This seems to be a regression as I've had the LED sample running on a nRF52840 DK before, but I don't have a specific version.

I along with ZMK (zmkfirmware/zmk#1746) ran into a similar issue. A few observations:

  • WS2812B worked fine on SPI0/SPI1/SPI2 when it was defined using the old sck-pin and mosi-pin. It only breaks with the new pinctrl definition.

This is a hardware limitation. All SPIM instances that share their resources with a TWIM (so the only exceptions are SPIM3 on nRF52840 and SPIM4 on nRF5340) cannot work without the SCK connected to a pin. This limitation was not apparent before pinctrl was introduced, because the sck-pin property was required and it was not possible to use a configuration without SCK. Now, with pinctrl, such configuration is achievable but it will not work for most SPI/SPIM instances.

  • It seems to work when pinctrl for SPI0/SPI1/SPI2 have NRF_PSEL(SPIM_SCK, ...) defined with an unused pin as a placeholder. SPI3 works both with and without SPIM_SCK defined.

Yes. And these are the only solutions for this issue: connect SCK to an unused pin or use SPIM3 (SPIM4 on nRF5340).

carlescufi commented 1 year ago

Closing as per the explanation provided by @anangl