adafruit / Adafruit_NeoPixel

Arduino library for controlling single-wire LED pixels (NeoPixel, WS2812, etc.)
GNU Lesser General Public License v3.0
3.05k stars 1.26k forks source link

Requesting Arduino Giga Wifi R1 Support (STM32H747) #349

Open MoveElectricMobility opened 1 year ago

MoveElectricMobility commented 1 year ago

Hello everyone! I recently moved from an Arduino Uno Wifi Rev 2 to the Arduino Giga Wifi R1 (STM32H747 based MCU) and this library stopped working, likely because support beyond the older Due board has not been built yet. If someone could add support for the Giga I would be very grateful, the new board is extremely popular. Thanks!

donemuhendislik commented 1 year ago

Sure, we need an urgent support for this topic too... All other libraries as FastLED is uncompatible with Arduino Giga Wifi R1 too... Thanks for your helps

Haschtl commented 1 year ago

I've created a fork which works with the Arduino GIGA. You can check it out here.

It may not be the optimal implementation, but it works.

Thanks to the takuya ichise for the codebase for STM32 (here).

Here is the main part (show()) of the implementation I added:

#if defined(TARGET_GIGA)
  // Arduino GIGA -----------------------------------------------------------
  uint8_t *p = pixels, *end = p + numBytes, pix;
  while (p < end)
  {
    pix = *p++;
    for (int i = 0; i < 8; i++)
    {
      // gpio_write(&gpio->gpio, 1);
      gpio->write(1);

      // duty cycle determines bit value
      // if (pix & 0x80)
      if (bitRead(pix, i) == 0)
      {
        // one
        // wait_ns(400); -> 192 cycles
        for (int j = 0; j < 96; j++)
          __NOP();

        // gpio_write(&gpio->gpio, 0);
        gpio->write(0);

        // wait_ns(850) -> 408 cycles
        for (int j = 0; j < 204; j++)
          __NOP();
      }
      else
      {
        // zero
        // wait_ns(800) -> 384 cycles
        for (int j = 0; j < 192; j++)
          __NOP();

        gpio->write(0);
        // gpio_write(&gpio->gpio, 0);
        // wait_ns(450) -> 216 cycles
        for (int j = 0; j < 108; j++)
          __NOP();
      }

      // pix = pix << 1; // shift to next bit
    }
  }
RobUnplanned commented 1 year ago

I have been used your fork - I am happy that it does give signal to the NeoPixel - but when doing a rainbow effect to test the functionality - noticed that it has trouble with finer RGBW values - so unsure if I have a different set up to you, or something else? I am using a Giga, and a typical hue loop.

tineira commented 9 months ago

@Haschtl thanks! its working perfectly.

Haschtl commented 9 months ago

I have been used your fork - I am happy that it does give signal to the NeoPixel - but when doing a rainbow effect to test the functionality - noticed that it has trouble with finer RGBW values - so unsure if I have a different set up to you, or something else? I am using a Giga, and a typical hue loop.

It depends on the library you are using for the NeoPixel. At the time I was programming my Giga project, I couldn't find any officially supporting the Giga. The timing in these libraries needs to be adapted for the Giga. It's also different for the main core and the second core.

My final solution that I can suggest when using NeoPixel is using the second core to control the NeoPixel pins and control it with via shared memory from the main core. This way your main-core is free and you have no problems with interrupts, because the timing critical part runs entirely on another core.

RubiCubix commented 6 months ago

Nice work. I noticed two things while I tested the fork. I am using ws2812b rgb led strips.

  1. For me it seems like the RGB order has changed compared to running the same code on my Arduino MEGA using the original Adafruit neopixel library.

  2. I am unable to set the color of the first neopixel on each led strip (separate IO pins). It's seems like when show() is called the first pixel i set to some random color no matter what. For instance, when I clear all pixels the first pixel remains green in my test.

Anyway, thanks for coming up with this code. It's one step towards stable support for the GIGA R1.

ABCartHub commented 5 months ago

Hello everyone, Thank you @Haschtl for your fork to adapt the library to GIGA R1! It's really useful to me! Great job. Like @RubiCubix, the first pixel of my strip lights green when all should be off. Did someone found a workaround? Thanks in advance!

geerbel commented 4 months ago

First of all, thanks to @Haschtl for providing a fork

As stated by @ABCartHub and @RubiCubix , I had the same issue that the first pixel always remained green. In addition, also the brightness settings messed up the color.

As reference, below the used components:

However I seem to found a solution for the colors, which works in my case. In the "Adafruit_NeoPixel.cpp" code of @Haschtl ; I changed the value of 'j' in the following code lines.

`#if defined(TARGET_GIGA) for (int j = 0; j < 80; j++)

else

    for (int j = 0; j < **40**; j++)

endif

      __NOP();

    // gpio_write(&gpio->gpio, 0);
    gpio->write(0);

    // wait_ns(850) -> 408 cycles

if defined(TARGET_GIGA)

    for (int j = 0; j < **170**; j++)

else

    for (int j = 0; j < **85**; j++)

endif

      __NOP();
  }
  else
  {
    // zero
    // wait_ns(800) -> 384 cycles

if defined(TARGET_GIGA)

    for (int j = 0; j < **160**; j++)

else

    for (int j = 0; j < **80**; j++)

endif

      __NOP();

    gpio->write(0);
    // gpio_write(&gpio->gpio, 0);
    // wait_ns(450) -> 216 cycles

if defined(TARGET_GIGA)

    for (int j = 0; j < **90**; j++)

else

    for (int j = 0; j < **45**; j++)

endif`

I doubt these are the 'perfect values', however it works.

Just for future reference in case somebody still needs it, as the current official AdaFruit Neopixel Library is still not supporting the Arduino Giga board.

tineira commented 2 weeks ago

I found the problem and a workarround for color correction. for some reason you have to send the colors with the bit order inverted.

you can get the correct color with this functions


uint8_t reveserBits(uint8_t val) {
    uint8_t valRev = 0;
    uint8_t bitMask  = B00000001;
    uint8_t bitWrite = B10000000;

    for(int i = 0; i < 8; i++) {
      if ((val & bitMask) > 0) {
        valRev = valRev | bitWrite;
      }
      bitMask = bitMask << 1;
      bitWrite = bitWrite >> 1;
    }

    return valRev;
}

 uint32_t getColor(uint8_t r, uint8_t g, uint8_t b){
     uint32_t color = reveserBits(r);
     color = color << 8;
     color += reveserBits(g);
     color = color << 8;
     color += reveserBits(b);

     return color;
 }
tineira commented 2 weeks ago

I've created a fork which works with the Arduino GIGA. You can check it out here.

It may not be the optimal implementation, but it works.

Thanks to the takuya ichise for the codebase for STM32 (here).

Here is the main part (show()) of the implementation I added:

#if defined(TARGET_GIGA)
  // Arduino GIGA -----------------------------------------------------------
  uint8_t *p = pixels, *end = p + numBytes, pix;
  while (p < end)
  {
    pix = *p++;
    for (int i = 0; i < 8; i++)
    {
      // gpio_write(&gpio->gpio, 1);
      gpio->write(1);

      // duty cycle determines bit value
      // if (pix & 0x80)
      if (bitRead(pix, i) == 0)
      {
        // one
        // wait_ns(400); -> 192 cycles
        for (int j = 0; j < 96; j++)
          __NOP();

        // gpio_write(&gpio->gpio, 0);
        gpio->write(0);

        // wait_ns(850) -> 408 cycles
        for (int j = 0; j < 204; j++)
          __NOP();
      }
      else
      {
        // zero
        // wait_ns(800) -> 384 cycles
        for (int j = 0; j < 192; j++)
          __NOP();

        gpio->write(0);
        // gpio_write(&gpio->gpio, 0);
        // wait_ns(450) -> 216 cycles
        for (int j = 0; j < 108; j++)
          __NOP();
      }

      // pix = pix << 1; // shift to next bit
    }
  }

if you change the for loop for this code, the correct colors are shown for (int i = 7; i >= 0; i--)