MrYsLab / NeoPixelConnect

A PIO based WS2812 NeoPixel library for the Arduino Nano RP2040 Connect, and Raspberry Pi Pico
GNU Affero General Public License v3.0
27 stars 4 forks source link

Going beyond BYTE size reels of WS2813 LEDs #1

Closed allthingsclowd closed 2 years ago

allthingsclowd commented 2 years ago

Hello MrYsLab,

Thank you so much for sharing this port for the pico controller. I have it working on the Arduino Nano RP2040 Connect with 300 (well 290 after some debug) LEDs.

I had some really unusual issues initially when I first tried testing the library. It transpires the library was initially configured for a BYTE of LEDs which does not go up to 300 - of course I went and bought the most dense reel could find.

This was a relatively straight forward fix once I discovered my challenge and thought I'd share it here for the awareness of any other late night tinkerers.

I changed the header as follows:

/*
 Copyright (c) 2020-2021 Alan Yorinks All rights reserved.

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 Version 3 as published by the Free Software Foundation; either
 or (at your option) any later version.
 This library is distributed in the hope that it will be useful,f
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 General Public License for more details.

 You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
 along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef NEOPIXEL_CONNECT_NEOPIXELCONNECT_H
#define NEOPIXEL_CONNECT_NEOPIXELCONNECT_H

#include <Arduino.h>
#include"stdio.h"
#include <stdlib.h>

#include "hardware/pio.h"
#include "hardware/dma.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"

#include "ws2812.pio.h"

#define MAXIMUM_NUM_NEOPIXELS 300

// Pixel buffer array offsets
#define RED 0
#define GREEN 1
#define BLUE 2

class NeoPixelConnect
{
public:
    /// @brief Constructor
    /// @param pinNumber: GPIO pin that controls the NeoPixel string.
    /// @param numberOfPixels: Number of pixels in the string
    NeoPixelConnect(byte pinNumber, int numberOfPixels);

    /// @brief Destructor
    virtual ~NeoPixelConnect(){};

    /// @brief Set a NeoPixel to a given color. By setting autoShow to true, change is
    /// displayed immediately.
    /// @param pixelNumber: set a color for a specific neopixel in the string
    /// @param r: red value (0-255)
    /// @param g: green value(0-255)
    /// @param b: blue value (0-255)
    /// @param autoShow: If true, show the change immediately.
    void neoPixelSetValue(uint16_t pixel_number, uint8_t r=0, uint8_t g=0, uint8_t b=0, bool autoShow=false);

    /// @brief Set all the pixels to "off".
    /// @param autoShow: If true, show the change immediately
    // set all pixels to 0
    void neoPixelClear(bool autoShow=true);

    /// @brief Fill all the pixels with same value
    /// @param r: red value (0-255)
    /// @param g: green value(0-255)
    /// @param b: blue value (0-255)
    /// @param autoShow: If true, show the change immediately.
    void neoPixelFill(uint8_t r=0, uint8_t g=0, uint8_t b=0, bool autoShow=true);

    /// @brief Display all the pixels in the buffer
    void neoPixelShow(void);

private:
    // pio - 0 or 1
    PIO pixelPio = pio0;

    // calculated program offset in memory
    uint pixelOffset;

    // pio state machine to use
    uint pixlSm = 0;

    // number of pixels in the strip
    int actual_number_of_pixels;

    // a buffer that holds the color for each pixel
    uint16_t pixelBuffer[MAXIMUM_NUM_NEOPIXELS][3];

    // write a color to a pixel
    static inline void putPixel(uint32_t pixel_grb) {
        pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
    }

    // create a 32 bit value combining the 3 colors
    static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
        return
                ((uint32_t) (r) << 8) |
                ((uint32_t) (g) << 16) |
                (uint32_t) (b);
    }

};

#endif //NEOPIXEL_CONNECT_NEOPIXELCONNECT_H

and the .cpp file to:

/*
 Copyright (c) 2020-2021 Alan Yorinks All rights reserved.

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 Version 3 as published by the Free Software Foundation; either
 or (at your option) any later version.
 This library is distributed in the hope that it will be useful,f
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 General Public License for more details.

 You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
 along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <NeoPixelConnect.h>

/// @brief Constructor
/// @param pinNumber: GPIO pin that controls the NeoPixel string.
/// @param numberOfPixels: Number of pixels in the string
NeoPixelConnect::NeoPixelConnect(byte pinNumber, int numberOfPixels){
    uint offset = pio_add_program(pixelPio, &ws2812_program);
    ws2812_program_init(pixelPio, 0, offset, pinNumber, 800000,
                false);

    // save the number of pixels in use
    this->actual_number_of_pixels = numberOfPixels;

    // set the pixels to the fill color
    for (int i = 0; i < this->actual_number_of_pixels; i++) {
        this->pixelBuffer[i][RED] = 0;
        this->pixelBuffer[i][GREEN] = 0;
        this->pixelBuffer[i][BLUE] = 0;
    }

    // show the pixels
    this->neoPixelShow();
    delay(1);

}

/// @brief Set a NeoPixel to a given color. By setting autoShow to true, change is
/// displayed immediately.
/// @param pixelNumber: set a color for a specific neopixel in the string
/// @param r: red value (0-255)
/// @param g: green value(0-255)
/// @param b: blue value (0-255)
/// @param autoShow: If true, show the change immediately.
void NeoPixelConnect::neoPixelSetValue(uint16_t pixelNumber, uint8_t r, uint8_t g, uint8_t b, bool autoShow){
    this->pixelBuffer[pixelNumber][RED] = r;
    this->pixelBuffer[pixelNumber][GREEN] = g;
    this->pixelBuffer[pixelNumber][BLUE] = b;
    if (autoShow) {
        this->neoPixelShow();
    }
}

/// @brief Set all the pixels to "off".
/// @param autoShow: If true, show the change immediately
void NeoPixelConnect::neoPixelClear(bool autoShow){
    // set all the neopixels in the buffer to all zeroes
    for (int i = 0; i < this->actual_number_of_pixels; i++) {
        this->pixelBuffer[i][RED] = 0;
        this->pixelBuffer[i][GREEN] = 0;
        this->pixelBuffer[i][BLUE] = 0;
    }
    if (autoShow) {
        this->neoPixelShow();
    }

}

/// @brief Fill all the pixels with same value
/// @param r: red value (0-255)
/// @param g: green value(0-255)
/// @param b: blue value (0-255)
/// @param autoShow: If true, show the change immediately.
void NeoPixelConnect::neoPixelFill(uint8_t r, uint8_t g, uint8_t b, bool autoShow){
    // fill all the neopixels in the buffer with the
    // specified rgb values.
    for (int i = 0; i < this->actual_number_of_pixels; i++) {
        this->pixelBuffer[i][RED] = r;
        this->pixelBuffer[i][GREEN] = g;
        this->pixelBuffer[i][BLUE] = b;
    }
    if (autoShow) {
        this->neoPixelShow();
    }

}

/// @brief Display all the pixels in the buffer
void NeoPixelConnect::neoPixelShow(void){
    // show the neopixels in the buffer
    for (int i = 0; i < this->actual_number_of_pixels; i++) {
        this->putPixel(urgb_u32(pixelBuffer[i][RED],
                           pixelBuffer[i][GREEN],
                           pixelBuffer[i][BLUE]));
    }
}

Thanks once again for sharing - this library saved me so much time.

MrYsLab commented 2 years ago

Thanks. I will incorporate this sometime in the future. I just released a library to allow you to control the Nano RP2040 Connect remotely using Python scripts. I will give it a week or so in case bugs are found, and then will modify both this library and the Telemetrix code to match it.

MrYsLab commented 2 years ago

Resolved with pull #5