Showing posts with label NeoPixels. Show all posts
Showing posts with label NeoPixels. Show all posts

Sunday, 29 December 2024

Pimoroni Plasma 2350

Raspberry Pi recently released the RP2350 microcontroller. There was a shortage of the corresponding Pico 2 development board, but other board manufacturers certainly filled the gap.

One of them was Pimoroni with a number of interesting offerings.

One of them is the Plasma 2350 Neopixel strip controller.

I already had a set of the RGB LED Star Wire 66 Neopixel strips, so I just bought the board.

The board is fully assembled and just requires the use of a jeweller's type screwdriver to attach the wires from the NeoPixel strip to the board using the terminal block. One thing to note is that unlike the Plasma Stick 2040W, the Plasma 2350 has a four connector terminal block. As you can see, the connections to use are 5V, Dat[a] and negative.

The board has one QWIC/STEMMA I2C connector, an on-board NeoPixel, three buttons (reset, boot and user button) and a connector labelled SP/CE. The latter is an SPI connector standard allowing higher speed connections to the board (such as WIFI).

What it does not have is WIFI or Bluetooth onboard (a later variant does but does not have the SP/CE connector, a Raspberry Pi RM2 Wireless module is directly wired to the board.)

Code

So to use the board and the LED string, some code is required.
This is the code for the main.py file.
The plasma2040 module in plasma works with the Pasma 2350.
The user interface is very simple. Pressing the User Button A cycles through the available light options.
The specific display uses Pythons' polymorphism to handle the basic operations. The method update() updates the display and is triggered (in this case) every half a second.
The light_show_base class (and its subtypes) determine what happens during the update. That code is in a separate file.

main.py

import plasma
from light_show_base import RGBElement, light_show_base, light_show_static_seven, light_show_static_seven_reverse, light_show_alternate
from plasma import plasma2040
from time import sleep
from pimoroni import RGBLED
# Set how many LEDs you have
NUM_LEDS = 66

led = RGBLED(16, 17, 18) 

# WS2812 / NeoPixel™ LEDs
led_strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT)

# Start updating the LED strip
led_strip.start()

display = light_show_base(led_strip, NUM_LEDS, led)
a_button = machine.Pin(12, machine.Pin.IN, machine.Pin.PULL_UP)

selected_pattern = 0

while True:
    display.update()
    if a_button.value() == 0:
        selected_pattern = selected_pattern + 1
        if selected_pattern > 5:
            selected_pattern = 0

        if selected_pattern == 0:
            display = light_show_base(led_strip, NUM_LEDS, led)
        elif selected_pattern == 1:
            display = light_show_static_seven(led_strip, NUM_LEDS, led)
        elif selected_pattern == 2:
            display = light_show_static_seven_reverse(led_strip, NUM_LEDS, led)
        elif selected_pattern == 3:
            display = light_show_alternate(led_strip, NUM_LEDS, led, RGBElement(255,0,0), RGBElement(0,255,0))
        elif selected_pattern == 4:
            display = light_show_alternate(led_strip, NUM_LEDS, led, RGBElement(0,0,255), RGBElement(255,255,0))
        elif selected_pattern == 5:
            display = light_show_alternate(led_strip, NUM_LEDS, led, RGBElement(0,255,0), RGBElement(255,255,255))
        print(selected_pattern)

    sleep(0.5)
    

light_show_base.py

The file contains two main classes: RGBElement and light_show_base.
There are also subclasses of class light_show_base, inheriting from light_show_base.
class RGBElement:
    def __init__(self,red, green,blue):
        self.red = red
        self.green = green
        self.blue = blue
    def __str__(self): 
        return f"{self.red} {self.green} {self.blue}"
        
class light_show_base:
    def __init__(self, led_strip, num_leds, rgb_led):
        # Device specific settings
        self.led_strip = led_strip
        self.rgb_led = rgb_led
        self.num_leds = num_leds
        
        # Chosen colour
        self.current_colour = 0
        
        # Base set of colours
        self.white = RGBElement(255,255,255)
        self.yellow = RGBElement(255,255,0)
        self.magenta = RGBElement(255,0,255)
        self.red = RGBElement(255,0,0)
        self.cyan = RGBElement(0,255,255)
        self.green = RGBElement(0,255,0)
        self.blue = RGBElement(0,0,255)
        self.black = RGBElement(0,0,0)
  
        # List of colours
        self.colours = [
            self.white,
            self.yellow,
            self.magenta,
            self.red,
            self.cyan,
            self.green,
            self.blue,
            self.black
            ] 

            
    def update(self):
        if self.current_colour == len(self.colours) - 1:
            self.current_colour = 0
        else:
            self.current_colour = self.current_colour + 1

        rgb_colour = self.colours[self.current_colour]
        self.rgb_led.set_rgb(rgb_colour.red, rgb_colour.green, rgb_colour.blue)
        for i in range(self.num_leds):
            self.led_strip.set_rgb(i, rgb_colour.green,rgb_colour.red, rgb_colour.blue)
        
class light_show_static_seven(light_show_base):
    def __init__(self, led_strip, num_leds, rgb_led):
        super().__init__(led_strip, num_leds, rgb_led)
        self.colour_strip = []
        ix = 0
        for i in range(self.num_leds):
            self.colour_strip.append(self.colours[ix])
            if ix == len(self.colours) - 1:
                ix = 0
            else:
                ix = ix +1
                
    def change_colours(self):
        last_colour = self.colour_strip[1]
        for i in range(self.num_leds):
            if i > 1:
                self.colour_strip[i - 1] = self.colour_strip[i]
        self.colour_strip[self.num_leds - 1] = last_colour
            
    def update(self):
        for i in range(self.num_leds):
            rgb_colour = self.colour_strip[i]           
            self.led_strip.set_rgb(i, rgb_colour.green,rgb_colour.red, rgb_colour.blue)
        rgb_colour = self.colour_strip[1] 
        self.rgb_led.set_rgb(rgb_colour.red, rgb_colour.green, rgb_colour.blue)

        self.change_colours()

class light_show_static_seven_reverse(light_show_static_seven):
    def __init__(self, led_strip, num_leds, rgb_led):
        super().__init__(led_strip, num_leds, rgb_led)

    def change_colours(self):
        last_colour = self.colour_strip[self.num_leds-1] 
        for i in range(self.num_leds-1):
            ix = self.num_leds - i
            print(ix)
            if ix < self.num_leds-1: 
                self.colour_strip[ix + 1] = self.colour_strip[ix]
        self.colour_strip[1] = last_colour            
        
class light_show_alternate(light_show_base):
     def __init__(self, led_strip, num_leds, rgb_led, led_one, led_two):
        super().__init__(led_strip, num_leds, rgb_led)
        self.led_one = led_one
        self.led_two = led_two

     def change_colours(self):
        temp = self.led_one
        self.led_one = self.led_two
        self.led_two = temp


     def update(self):
        led_one = self.led_one
        led_two = self.led_two
        self.rgb_led.set_rgb(led_one.red, led_one.green, led_one.blue)
        for i in range(self.num_leds/2):
            self.led_strip.set_rgb(i * 2, led_one.green,led_one.red, led_one.blue)
            self.led_strip.set_rgb(i * 2+1, led_two.green,led_two.red, led_two.blue)
        self.change_colours()

References


Sunday, 24 November 2024

Adafruit RP2040 Prop-Maker Feather - Staser sound effect

This uses the Prop-Maker Feather'’s I2S audio amplifier to generate a sound effect, in this case a Gallifreyan Staser sound effect.





For testing purposes, the sound is triggered by the use of the Boot button on the board (the Boot button on the Prop-Maker Feather is connected to GPIO7 and named board.Button in CircuitPython)

For use as a prop, the trigger would be wired to the Button terminal and the Ground terminal shared with the NeoPixel.

Getting your sound effect.

The Prop-Maker Feather requires a PCM 16-bit Mono WAV files at a sample rate of 22KHz. This can be created using Audicity by following the Adafruit instructions.

Code

# Staser sound effect
import board
import digitalio
import time
import neopixel
import random
import audiocore
import audiobusio
import audiomixer
import pwmio
import keypad

keys = keypad.Keys((board.BUTTON,), value_when_pressed=False, pull=True)

# One of the features of the prop-maker is that the Neopixel
# (and the amplifier and the speaker) can be switched on and off
external_power = digitalio.DigitalInOut(board.EXTERNAL_POWER)
external_power.direction = digitalio.Direction.OUTPUT
external_power.value = True

audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)

def play(filename, audio):
    # i2s playback
    wave_file = open(filename, "rb")
    wave = audiocore.WaveFile(wave_file)
    mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1,
                         bits_per_sample=16, samples_signed=True)
    audio.play(mixer)
    mixer.voice[0].play(wave, loop=False)
    mixer.voice[0].level = 0.5
    print("Fire")
    wave_file

while True:
    event = keys.events.get()
    # event will be None if nothing has happened.
    if event:
        if event.pressed:
            play("staser.wav",audio)

print("Done")

References

https://learn.adafruit.com/adafruit-rp2040-prop-maker-feather/overview

https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keys-one-key-per-pin

https://learn.adafruit.com/microcontroller-compatible-audio-file-conversion

https://learn.adafruit.com/lightsaber-rp2040/code-the-lightsaber


Adafruit RP2040 Prop-Maker Feather

The Adafruit RP2040 Prop-Maker Feather is an Adafruit Feather format board using the Raspberry Pi RP2040 processor with 8MB of QSPI FLASH with a terminal block connector at one end, QWIC/STEMMA connector, Servo connector and adjacent to the USB type C connector a battery connector (with charging capability). It can be used without any soldering.


There is a slightly more in-depth discussion here.

The terminal block has three connections for the NeoPixels (5V, ground and data), two for a 4-8 ohm speaker and one for a button.

Assembly

This set up is going to use a 500mm strip of 332 LED per metre ultra dense strip.

It is supplied with a female connector and a matching male connector with wires to connect to the Feather’s terminals.

Unfortunately, due to not completely comprehending the operation of the NeoPixel driver, I went through a number of iterations on connection, including removing the connector on the strip before finally realising that the NeoPixel driver is by default OFF, and a pin needs to be set to make it (and the speaker driver) live. Once that was set and the wires appropriately connected everything was fine.

Installation

CircuitPython is derived from MicroPython and makes the device appear as a USB storage device on the host computer.

This means that any editor can be used to edit the CircuitPython source as long as when it saves, it saves everything to the device.

I use a slightly different method, I have a simple Visual Studio program that I use to copy all the required files to the device - and develop using Visual Studio Code. This means that there is always a copy of the code on the laptop in the event that the device becomes unreadable.

The alternative is to use an IDE like MU.

Download the latest version of CircuitPython for the board from the CircuitPython site.

Connect the Prop-Maker Feather to the computer with a known good data (not charge only cable).

The Prop-Maker Feather has a Reset and a Boot Select button. This makes entering the Bootloader a lot easier tan having to unplu and plug the device in while holding down a tiny button.

Hold down the BOOT button and while continuing to hold it, press and release the reset button. Keep holding the BOOT button until a RPI-RP2 drive on the computer.

Copy and paste the UF2 file into the drive. When it has finished copying, the Feather will reboot.

Coding

This program repeatedly through runs the NeoPixel strip through a number of colours. The onboard LED is flashed during each cycle.

# Imports

import board

import digitalio

import time

import neopixel


# Use the builtin LED as a pulse

led = digitalio.DigitalInOut(board.LED)

led.direction = digitalio.Direction.OUTPUT


# Set a list of colour combinations

COLORS = (

    (255,   0,   0),

    (  0, 255,   0),

    (  0,   0, 255),

    (255, 255,   0),

    (255,   0, 255),

    (  0, 255, 255),

)

# Set up Neopixels

# This is for a 0.5m Ultra-dense RGB Micro LED Strip with 332 LEDs per metre

num_pixels = 165

pixels = neopixel.NeoPixel(board.EXTERNAL_NEOPIXELS, num_pixels, auto_write=True)

pixels.brightness = 0.02

# One of the features of the prop-maker is that the Neopixel 

# (and the amplifier and the speaker) can be switched on and off 

external_power = digitalio.DigitalInOut(board.EXTERNAL_POWER)

external_power.direction = digitalio.Direction.OUTPUT

external_power.value = True


# Loop indefinitely

while True:

    # Loop through the colour list

    for color in COLORS:

        # Set the built in LED on

        led.value = True

        time.sleep(0.5)

        # Set each pixel in turn

        for i in range(num_pixels):

            pixels[i] = color

        pixels.show()

        # Set the built in LED off

        led.value = False

        time.sleep(0.5)

Here is the device in action.



References

https://shop.pimoroni.com/products/adafruit-rp2040-prop-maker-feather-with-i2s-audio-amplifier?variant=41128910454867

https://shop.pimoroni.com/products/neon-like-rgb-micro-led-strip?variant=39395564585043

https://circuitpython.org/board/adafruit_feather_rp2040_prop_maker/

https://circuitpython.org/libraries

https://learn.adafruit.com/adafruit-rp2040-prop-maker-feather/overview

https://learn.adafruit.com/lightsaber-rp2040/code-the-lightsaber



Sunday, 25 December 2022

Adafruit QT Py RP2040

Introduction

The Adafruit QT Py is a range of diminutive development boards. The QT Py pinout and shape is Seeed Xiao compatible and has castellated pads to allow it to be soldered to a PCB (note, some boards have components on the bottom of the board so will require a cut-out - this is one of them).

The boards have a QWIIC socket. It also has an RGB Neopixel.

Adafruit have released a version using the Raspberry Pi RP2040 processor (which requires a double-sided board to fit all the bits in the format).

It is quite a lot smaller than the Raspberry Pi PICO.
As you can see, the board, unlike the PICO is double sided. To solder it to another board, quite substantial cut outs would be required in the other board.

The QWIIC socket allows suitable I2C breakout boards to be connected without soldering. In this case a cable connected to the QT Py is connected to a PIMORONI BreakOut Garden adaptor (with a 1.12" OLED display).

Adafruit recommend CircuitPython but there is also an official MIcroPython port.However, there is little or no documentation on programming the board beyond that for a vanilla PICO.

Installing MicroPython

Download the UF2 file from the MicroPython site. If you are downloading onto a Windows machine, right click on the downloaded file, select Properties and Unblock 

Plug a USB A to USB C data cable into the board and the computer.

Hold the BOOTSEL button and press the RESET button.

The board will appear as a drive.

Copy the UF2 file to the board.

Once it has finished downloading, the board will restart.

Blink

The QT Py RP2040 has a Neopixel rather than the traditional LED on pin 13. This means that the normal Blink program does not work.

The CircuitPython UF2 specifically for the board has built in functions to operate the RGB Neopixel, and the board library has constants for the Neopixel pin.

I was unable to locate a Micropython example for the Blink program using a Neopixel.

Checking the pin-out https://learn.adafruit.com/assets/107201 shows that the RGB Neopixel is on pin 12, and the power for the Neopixel is on pin 11. To make the board more power efficient (useful for a battery powered application), the Neopixel can be unpowered in addition to not displaying a colour.

This requires both the Neopixel pin to be passed to the Neopixel constructor, and the power pin set to on.

Code

import time
import machine
import neopixel
# Set up a single Neopixel
pin = machine.Pin(12, machine.Pin.OUT)
pixel = neopixel.NeoPixel(pin, 1)
pixel.brightness = 0.3
# Set the power pin high to activate the Neopixel
power_pin = machine.Pin(11, machine.Pin.OUT)
power_pin.on()
def set_pixel(rgb):
    # Set the first pixel to rgb
    pixel[0] = rgb
    # Write the setting to the Neopixel
    pixel.write()
while True:
    # Set the first pixel to Red
    set_pixel((255, 0, 0))
    time.sleep(0.5)
    # Set the first pixel to off
    set_pixel((0, 0, 0))
    time.sleep(0.5)
    print("Blink!")


References

https://micropython.org/download/ADAFRUIT_QTPY_RP2040/

https://www.adafruit.com/category/1005

https://learn.adafruit.com/adafruit-qt-py/overview

https://shop.pimoroni.com/products/adafruit-qt-py-rp2040?variant=39341945487443

https://learn.adafruit.com/adafruit-qt-py-2040/blink

https://docs.micropython.org/en/latest/rp2/quickref.html#neopixel-and-apa106-driver

https://docs.micropython.org/en/latest/rp2/quickref.html#i2s-bus


 

Friday, 21 May 2021

Adafruit Trinkey

The Adafruit Trinkey is a tiny USB key format microcontroller with four Neopixels and an M0 processor.

 


The end opposite the USB contact can function as two touch sensitive buttons.

I bought mine from Pimoroni.

When plugged into the USB port of my Debian laptop, it failed to register. I thought it might be an issue with connecting to an elderly ex-Windows laptop. So I tried it on a Windows laptop. Still it did not register. The Neopixels worked, and the touch sensors started and stopped the display.

However, when set to Boot Mode (double press on the reboot button) it registered as a USB device.

I then downloaded the latest version of CircuitPython from https://circuitpython.org/board/neopixel_trinkey_m0/

This was then copied to the device which then causes the device to restart. The device now appeared as a USB memory device.

Programming

CircuitPython devices are simple to program, appearing as a USB memory device. Saving a new file to the device causes it to restart. Generally the file code.py is executed on starting.

Adafruit's recommendation is to use the Mu editor. This writes directly to the CircuitPython device. It does however mean you need to be particularly careful that you have a copy of the code somewhere.

To make my life easier, I put together a simple Visual Studio program to copy specific code.py files from specific folders. I then edited the code using Visual Studio Code.

Example code

The example code is derived from the code from the Neo Trinkey Zoom Short Cut project (see references)

import time
import board
import neopixel

#  setup for onboard neopixels
pixel_pin = board.NEOPIXEL
num_pixels = 4

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.05, auto_write=False)

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        return (0, 0, 0)
    if pos < 85:
        return (255 - pos * 3, pos * 3, 0)
    if pos < 170:
        pos -= 85
        return (0, 255 - pos * 3, pos * 3)
    pos -= 170
    return (pos * 3, 0, 255 - pos * 3)

def rainbow_cycle(wait):
    for j in range(255):
        for i in range(num_pixels):
            rc_index = (i * 256 // num_pixels) + j
            pixels[i] = wheel(rc_index & 255)
        pixels.show()
        time.sleep(wait)

while True:
    rainbow_cycle(0.001)

References

https://www.adafruit.com/product/4870
https://circuitpython.org/board/neopixel_trinkey_m0/

Wednesday, 25 December 2019

Merry Christmas

At this festive time of year, here is a flashing Christmas ornament.


This is an Adafruit Circuit Playground Express in an enclosure powered by a USB power block.