LuckfoxTECH / luckfox-pico

luckfox-pico sdk
241 stars 82 forks source link

control WS2812B LEDs #135

Open KaliAssistant opened 1 week ago

KaliAssistant commented 1 week ago

is possible use rpi_ws281x and adafruit-circuitpython-neopixel to control ws2812b rgb led just like raspberry pi?

plan44 commented 1 week ago

I hope this is possible, maybe by leveraging pne of the PWMs of which 2 units apparently can send IR data? Is there any detail docs about the RV1106 PWM? I have written a PWM based WS28xx kernel driver for the Mediatek MT7688, and would very much like to port it to RV1106, once I can obtain docs.

KaliAssistant commented 1 week ago

I will try it. I don’t have hardware now

nopnop2002 commented 3 days ago

adafruit-circuitpython-neopixel library is based on Adafruit Blinka.

https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel/blob/main/requirements.txt

Adafruit Blinka supports pico board.

adafruit-circuitpython-neopixel library may work with pico board.

KaliAssistant commented 3 days ago

@nopnop2002 I installed rpi_ws281x and adafruit-circuitpython-neopixel , i run the code ,it says gpio not support this board

KaliAssistant commented 3 days ago

it still using RPI.gpio

KaliAssistant commented 3 days ago

I use 0.5 days to install pip pkg

nopnop2002 commented 3 days ago

i run the code ,it says gpio not support this board

https://github.com/adafruit/Adafruit_Blinka/blob/main/src/adafruit_blinka/board/luckfox/luckfoxpico_mini.py

I use 0.5 days to install pip pkg

python3 -m pip install Adafruit-Blinka==8.43.0

Installation took about 10 minutes on the pico mini board using RNDIS.

from 8.44.0, installation will take longer.

SSD1306 also works well.

Pico-Min-SSD1306-1

KaliAssistant commented 2 days ago

@nopnop2002 thanks i will try it.

nopnop2002 commented 2 days ago

Performance will be slightly faster if you use a 16GB or larger SD card and expand SWAP.

$ sudo mkswap /dev/mmcblk1p8
Setting up swapspace version 1, size = 54726455296 bytes

$ sudo swapon /dev/mmcblk1p8
[  105.830584] Adding 53443804k swap on /dev/mmcblk1p8.  Priority:-2 extents:1 across:53443804k SS

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            33Mi        13Mi       2.0Mi       0.0Ki        17Mi        16Mi
Swap:          8.7Gi        15Mi       8.7Gi
KaliAssistant commented 2 days ago

This is very harmful to the sd card...

nopnop2002 commented 2 days ago

This is very harmful to the sd card...

Why?

KaliAssistant commented 2 days ago

This is very harmful to the sd card...

Why?

Just like you make a very slow ram on sd card...

KaliAssistant commented 2 days ago

@nopnop2002 same...

pico@foxjack:~/python3$ sudo ./.venv/bin/python3
[sudo] password for pico:
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gpiod
>>> import board
>>> import neopixel
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pico/python3/.venv/lib/python3.10/site-packages/neopixel.py", line 18, in <module>
    from neopixel_write import neopixel_write
  File "/home/pico/python3/.venv/lib/python3.10/site-packages/neopixel_write.py", line 41, in <module>
    raise NotImplementedError("Board not supported")
NotImplementedError: Board not supported
>>>
luckfox-eng33 commented 2 days ago

If you don't use SPI, you can theoretically use SPI's MOSI pins to control WS2812B

rpi_ws281x has two options

  1. Based on the PWM register and DMA of Raspberry Pi, it is difficult to implement on RV1103/6
  2. Using SPI for simulation is not difficult to implement.
KaliAssistant commented 2 days ago

I run my code

pico@foxjack:~/python3$ sudo ./.venv/bin/python3 ./neotest 
[sudo] password for pico: 
Traceback (most recent call last):
  File "/home/pico/python3/./neotest", line 97, in <module>
    strip.begin()
  File "/home/pico/python3/.venv/lib/python3.10/site-packages/rpi_ws281x/rpi_ws281x.py", line 143, in begin
    raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, str_resp))
RuntimeError: ws2811_init failed with code -3 (Hardware revision is not supported)
Segmentation fault

code:

#!/usr/bin/env python3
# NeoPixel library strandtest example
# Author: Tony DiCola (tony@tonydicola.com)
#
# Direct port of the Arduino NeoPixel library strandtest example.  Showcases
# various animations on a strip of NeoPixels.

import time
from rpi_ws281x import PixelStrip, Color
import argparse

# LED strip configuration:
LED_COUNT = 1        # Number of LED pixels.
LED_PIN = 50          # SPI ? idk 
LED_FREQ_HZ = 800000  # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10          # ?
LED_BRIGHTNESS = 255  # Set to 0 for darkest and 255 for brightest
LED_INVERT = False    # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0       # set to '1' for GPIOs 13, 19, 41, 45 or 53

# Define functions which animate LEDs in various ways.
def colorWipe(strip, color, wait_ms=50):
    """Wipe color across display a pixel at a time."""
    for i in range(strip.numPixels()):
        strip.setPixelColor(i, color)
        strip.show()
        time.sleep(wait_ms / 1000.0)

def theaterChase(strip, color, wait_ms=50, iterations=10):
    """Movie theater light style chaser animation."""
    for j in range(iterations):
        for q in range(3):
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, color)
            strip.show()
            time.sleep(wait_ms / 1000.0)
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, 0)

def wheel(pos):
    """Generate rainbow colors across 0-255 positions."""
    if pos < 85:
        return Color(pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return Color(255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return Color(0, pos * 3, 255 - pos * 3)

def rainbow(strip, wait_ms=20, iterations=1):
    """Draw rainbow that fades across all pixels at once."""
    for j in range(256 * iterations):
        for i in range(strip.numPixels()):
            strip.setPixelColor(i, wheel((i + j) & 255))
        strip.show()
        time.sleep(wait_ms / 1000.0)

def rainbowCycle(strip, wait_ms=20, iterations=5):
    """Draw rainbow that uniformly distributes itself across all pixels."""
    for j in range(256 * iterations):
        for i in range(strip.numPixels()):
            strip.setPixelColor(i, wheel(
                (int(i * 256 / strip.numPixels()) + j) & 255))
        strip.show()
        time.sleep(wait_ms / 1000.0)

def theaterChaseRainbow(strip, wait_ms=50):
    """Rainbow movie theater light style chaser animation."""
    for j in range(256):
        for q in range(3):
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, wheel((i + j) % 255))
            strip.show()
            time.sleep(wait_ms / 1000.0)
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, 0)

# Main program logic follows:
if __name__ == '__main__':
    # Process arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
    args = parser.parse_args()

    # Create NeoPixel object with appropriate configuration.
    strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
    # Intialize the library (must be called once before other functions).
    strip.begin()

    print('Press Ctrl-C to quit.')
    if not args.clear:
        print('Use "-c" argument to clear LEDs on exit')

    try:

        while True:
            print('Color wipe animations.')
            colorWipe(strip, Color(255, 0, 0))  # Red wipe
            colorWipe(strip, Color(0, 255, 0))  # Green wipe
            colorWipe(strip, Color(0, 0, 255))  # Blue wipe
            print('Theater chase animations.')
            theaterChase(strip, Color(127, 127, 127))  # White theater chase
            theaterChase(strip, Color(127, 0, 0))  # Red theater chase
            theaterChase(strip, Color(0, 0, 127))  # Blue theater chase
            print('Rainbow animations.')
            rainbow(strip)
            rainbowCycle(strip)
            theaterChaseRainbow(strip)

    except KeyboardInterrupt:
        if args.clear:
            colorWipe(strip, Color(0, 0, 0), 10)

idk what gpio num should i use in my code 2024-07-05_12-57-46

nopnop2002 commented 1 day ago

Adafruit CircuitPython NeoPixel only supports these boards.

if detector.board.any_raspberry_pi:
    from adafruit_blinka.microcontroller.bcm283x import neopixel as _neopixel
elif detector.board.pico_u2if:
    from adafruit_blinka.microcontroller.rp2040_u2if import neopixel as _neopixel
elif (
    detector.board.feather_u2if
    or detector.board.feather_can_u2if
    or detector.board.feather_epd_u2if
    or detector.board.feather_rfm_u2if
    or detector.board.qtpy_u2if
    or detector.board.itsybitsy_u2if
    or detector.board.macropad_u2if
    or detector.board.qt2040_trinkey_u2if
    or detector.board.kb2040_u2if
):
    from adafruit_blinka.microcontroller.rp2040_u2if import neopixel as _neopixel
elif "sphinx" in sys.modules:
    pass
else:
    raise NotImplementedError("Board not supported")
plan44 commented 15 hours ago

If you don't use SPI, you can theoretically use SPI's MOSI pins to control WS2812B The RV1106 has two SPI units - only SPI0 is exposed on the LuckFox pico's pins. I guess the internal NAND-Flash is also connected via SPI, is that on SPI1? If so, SPI0 would be free 😄

  1. Using SPI for simulation is not difficult to implement.

Yes, if you can set the SPI to ~2.8Mhz bit clock, then sending 0xC and 0x8 nibbles for H and L bits, respectively, works fine (implemented this on another platforms some years ago). The wiki has good information about SPI programming: https://wiki.luckfox.com/Luckfox-Pico/Luckfox-Pico-SPI#4-spi-communication-c-program

I will try this as soon as I get my OpenWrt flashed onto the pico max, but I am stuck with that right now...