Overview
The Pixel Framebuf library makes drawing to a grid of NeoPixels or DotStars as easy as writing to a display. The library has all of the drawing functions of the original framebuf library, including the ability to draw lines, circles, rectangles, and text.
This library can be used on a wide variety of NeoPixel and DotStar LED layouts including with flexible and non-flexible matrices, NeoPixels strips laid out by hand, or FeatherWings. This library has been tested to work with both CircuitPython Microcontrollers and Blinka on the Raspberry Pi.
One of the huge advantages that using NeoPixel and DotStar LED matrices has over the standard RGB LED matrices is that they only use one or two GPIO pins. The Pixel Framebuf library gives you the simplicity and control to make use of these matrices to display data in a meaningful way in much the same way that you can on RGB matrices.
NeoPixels take a lot of power, so a 5V 4 Amp or even a 10 Amp power supply is recommended.
Page last edited March 08, 2024
Text editor powered by tinymce.
Wiring
To make wiring simple, we recommend a couple of different products available in our store. First we recommend a DC Power jack with terminals so it's easy to connect up to an external power supply.
The other product that makes it easy if you have one of our NeoPixel Matrices is a 2-wire JST SM connector so you can use the the data line without cutting anything:
Likewise, if you have one of our DotStar Matrices, we have a 4-wire version as well:
Another easy option to connect NeoPixels is to use some Jumper Wires:
NeoPixel Matrix Wiring
Wiring the pixels up to either a Microcontroller running CircuitPython or a Raspberry Pi running Blinka is very easy since either one only uses a single GPIO pin. Adafruit matrices come wired with separate power wires and data lines which makes it really easy to connect.
CircuitPython Wiring
It is recommended using a microcontroller with an M4 processor, because it can drive a lot of NeoPixels fast and doesn't cost much more than an M0 board.
To connect it, you will need to wire it as follows:
- Connect the red wire to +5V on the power supply.
- Connect the black wire to Ground on the power supply
- Connect the white DIN wire of the female JST connector to D6 on the Microcontroller
- Connect the black wire of the female JST connector to Ground on the Microcontroller
Raspberry Pi Wiring
Raspberry Pi boards are powerful enough to drive lots of NeoPixels, but you will need to connect it to GPIO10, GPIO12, GPIO18 or GPIO21 to work! We recommend GPIO18, which is Pin 12 on the 40-pin header.
To connect it, you will need to wire it as follows:
- Connect the red wire to +5V on the power supply.
- Connect the black wire to Ground on the power supply
- Connect the white wire of the JST connector to GPIO18 (Pin 12) on the Microcontroller
- Connect the black wire of the JST connector to Ground (Pin 6) on the Microcontroller
For more information on wiring other configurations, be sure to check out our Adafruit NeoPixel Überguide.
DotStar Wiring
Wiring the DotStar matrix up will only take up two GPIO pins. Adafruit matrices come wired with separate power wires and a connector with the power, data, and clock lines in a single connector, which makes them easy to chain together. For a very in-depth guide on DotStars and wiring them up in various configurations, be sure to checkout the Adafruit DotStar LEDs guide.
Page last edited March 08, 2024
Text editor powered by tinymce.
Import and Setup
The Pixel Framebuf library is designed to make adding text and graphics super simple. It is built on top of the very capable LED Animation and framebuf libraries and because of the flexibility provided by those libraries, it works on a wide variety of NeoPixel and DotMatrix displays and layouts.
CircuitPython Setup
To get the required libraries for this guide, download the latest CircuitPython library bundle from circuitpython.org.
Open the downloaded zip and find the following folder and files within the lib folder:
- adafruit_pixel_framebuf.mpy
- adafruit_framebuf.mpy
- adafruit_led_animation
If you are using NeoPixels, you will also need:
- neopixel.mpy
Or if you are using DotStar LEDs, you will need:
- adafruit_dotstar.mpy
Drag this folder and files to the lib folder on your CIRCUITPY drive.
Python Setup
You'll need to install the Adafruit_Blinka library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3. Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready!
Run NeoPixels on the Raspberry Pi requires the sudo command, so you will need to make sure you have the necessary libraries installed using sudo pip3.
Since Pip does a great job of handling dependencies, there's only a few commands you will need to run to get this set up:
pip3 install adafruit-circuitpython-pixel-framebuf
If you are running NeoPixels, you will also need the NeoPixel library:
pip3 install adafruit-circuitpython-neopixel
If you are running DotStars, you will also need the DotStar library:
pip3 install adafruit-circuitpython-dotstar
You will also need the Pillow library if you want to make use of the image() function:
pip3 install Pillow
Raspberry Pi requires a hardware PWM pin to drive the NeoPixels. We recommend D18, so you will need to change that in the code below if you any place you see D6.
Font File
If you want to display text, you will also need to include the font file. This font is included in the adafruit_framebuf library examples.
Place the font file in the same folder as you code.
Import and Object Setup
This library should work with either NeoPixels or DotStar LEDs. We are going to start by showing you how to use them with NeoPixels.
NeoPixels
The first thing you will need to do to run this library is to import the necessary libraries. An example of import and setup for the NeoPixel FeatherWing is as follows:
import board
import neopixel
from adafruit_pixel_framebuf import PixelFramebuffer
pixel_pin = board.D6
pixel_width = 8
pixel_height = 4
pixels = neopixel.NeoPixel(
pixel_pin,
pixel_width * pixel_height,
brightness=0.1,
auto_write=False,
)
First you import board and neopixel. Next import the PixelFramebuffer module. On certain NeoPixel displays, you may also need to import VERTICAL as well, which we'll cover in the Initialization section.
Next you'll want to set a few convenience variables including the pixel_pin, which is the pin that the NeoPixel data line is connected to. The pixel_width and pixel_height are there to help make the code more readable and correspond to the number of pixels wide and number of pixels high.
Finally, create the pixel object. You'll want to make sure auto_write is set to False so you don't see every single time an individual pixel is changed, which can be quite slow.
This guide will use NeoPixels for all the examples, but the Pixel Framebuf library works equally well with DotStar LEDs.
DotStar LEDs
The only change you would need to make to use this library with DotStar LEDs would be to initialize the DotStar library instead of the NeoPixel library. An example of import and setup for the DotStar FeatherWing is as follows:
import board
import adafruit_dotstar
from adafruit_pixel_framebuf import PixelFramebuffer
pixel_pin = board.D6
pixel_width = 12
pixel_height = 6
pixels = adafruit_dotstar.DotStar(
board.D13,
board.D11,
pixel_width * pixel_height,
brightness=0.3,
auto_write=False,
)
This example imports the necessary modules and assigns the appropriate pins and number of pixels to use 72 DotStar LEDs connected to D13 and D11.
Page last edited March 08, 2024
Text editor powered by tinymce.
Usage
Using the Pixel Framebuf library is easy. The most complicated part of it is the initialization, because it can vary so widely with each specific setup, so start with that and then go over each of the functions available to you.
Initialization
For initialization, we'll go over the different options and what the specific parameters mean so you can best determine which options to change for your setup.
-
pixels- (required) The NeoPixels or DotStars object that you initialized -
width- (required) The width of the framebuf in pixels. -
height- (required) The height of the framebuf in pixels. -
orientation- The direction that the pixels are physically laid out in either columns or rows. The value isHORIZONTALby default and you will need to importVERTICALif you want to set the value toVERTICAL. -
alternating- If the pixels zigzag, you will want to set this to True. If they are laid out in the same direction, you will want to set this to False. The default value is True. -
reverse_x- Set this to True if you want to reverse the direction of all pixels horizontally. -
reverse_y- Set this to True if you want to reverse the direction of all pixels vertically. -
top- An optional tuple representing the top left pixel. -
bottom- An optional tuple representing the bottom right pixel. -
rotation- A value between 0 and 3 representing the initial rotation of the Framebuffer. This can also be set later with therotationproperty.
Example Initializations
Here are the initializations for a few of the panels we have available. In these examples, it is assumed that you have done the necessary imports and setup as described on the Import and Setup page and that your NeoPixels or DotStars are named pixels.
pixel_framebuf = PixelFramebuffer(
pixels,
32,
8,
orientation=VERTICAL,
rotation=2
)
pixel_framebuf = PixelFramebuffer(
pixels,
16,
16,
reverse_x=True,
)
pixel_framebuf = PixelFramebuffer(
pixels,
8,
4,
alternating=False,
)
pixel_framebuf = PixelFramebuffer(
pixels,
12,
6,
alternating=False,
)
Drawing Functions
All drawing functions are based on coordinates starting from the upper left-hand side as the starting point.
Displaying the Framebuffer
Each time you want to display the current Framebuffer, you will need to call the display() function. This function takes no parameters and displays whatever is currently in memory. We will show you how to use it in each of the drawing function example code snippets.
Fill
To fill in the entire Framebuffer with a specific color, you can use the fill() function. For instance, to fill it with Blue (0x0000FF), you would use the following command:
pixel_framebuf.fill(0x0000FF) pixel_framebuf.display()
To turn all the pixels off, you can set them to 0x000000.
pixel_framebuf.fill(0x000000) pixel_framebuf.display()
Pixel Drawing
To draw a pixel, you just need to use the pixel() function and provide the coordinates and color. For instance, if you wanted to draw a set the pixel at (4, 6) to red, you would use the following command:
pixel_framebuf.pixel(4, 6, 0xFF0000) pixel_framebuf.display()
If you wanted to get the pixel's value, you would retrieve it like this:
color = pixel_framebuf.pixel(4, 6)
Line Drawing
To draw a line, you just need to to use the line() function and provide the starting coordinates, ending coordinates, and color. For instance, if you wanted to draw a line from (0, 0) to (7, 9) in red (0xFF0000), you would use the following command:
pixel_framebuf.line(0, 0, 7, 9, 0xFF0000) pixel_framebuf.display()
Horizontal and Vertical Line Drawing
To draw horizontal or vertical, you can use the hline() and vline() functions. These are optimized for fast drawing because they don't need to calculate a slope. You just need to pass the x and y coordinates along with the length of the line in pixels and the color you wish to draw.
To use these functions, to draw a 5 pixel red line starting at (2, 3), you would use the following:
pixel_framebuf.hline(2, 3, 5, 0xFF0000) pixel_framebuf.vline(2, 3, 5, 0xFF0000) pixel_framebuf.display()
Rectangle Drawing
To draw a non-filled Rectangle, you will want to use the rect() function. You provide it starting coordinates, width, height, and line color. To draw a red rectangle at (2, 2) with a width of 8 and a height of 12, you would use:
pixel_framebuf.rect(2, 2, 8, 12, 0xFF0000) pixel_framebuf.display()
To draw a filled rectangle, you would do the same thing with the fill_rect() function:
pixel_framebuf.fill_rect(2, 2, 8, 12, 0xFF0000) pixel_framebuf.display()
Text Drawing
To draw text, you would use the text() function, provide the string, upper left coordinates of the text, and the color. For instance, to draw "Hi" at (3, 4) in green (0x00FF00), you would use the following:
pixel_framebuf.text("Hi", 3, 4, 0x00FF00)
pixel_framebuf.display()
Text can go off the screen and simply redrawing the text in different positions on top of the same background can produce an animated text effect.
Page last edited March 08, 2024
Text editor powered by tinymce.
Image Drawing with Python
If you are using CPython on Linux, you can also make use of the Pillow library and the image function to draw images to the display. The only limitations are the image needs to be the exact same size as the Framebuffer and needs to be in RGB mode.
We're going to go over an example for running this. First download the blinka_16x16.png image and upload it to the folder that you plan to run the script in.
Next download the pixel_framebuf_pillow_image.py example, which is available in the Library repo:
# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams, written for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
Be sure to check the learn guides for more usage information.
This example is for use on (Linux) computers that are using CPython with
Adafruit Blinka to support CircuitPython libraries. CircuitPython does
not support PIL/pillow (python imaging library)!
Author(s): Melissa LeBlanc-Williams for Adafruit Industries
"""
import board
import neopixel
from PIL import Image
from adafruit_pixel_framebuf import PixelFramebuffer
pixel_pin = board.D18
pixel_width = 16
pixel_height = 16
pixels = neopixel.NeoPixel(
pixel_pin,
pixel_width * pixel_height,
brightness=0.1,
auto_write=False,
)
pixel_framebuf = PixelFramebuffer(
pixels,
pixel_width,
pixel_height,
reverse_x=True,
)
# Make a black background in RGBA Mode
image = Image.new("RGBA", (pixel_width, pixel_height))
# Open the icon
icon = Image.open("blinka_16x16.png")
# Alpha blend the icon onto the background
image.alpha_composite(icon)
# Convert the image to RGB and display it
pixel_framebuf.image(image.convert("RGB"))
pixel_framebuf.display()
Run the code.
sudo python3 pixel_framebuf_pillow_image.py
You should see an output similar to below:
How It Works
Below describes what is going on. You may recognize much of it from the previous section.
First start with imports. In addition to the usual imports, also import Image from the Pillow library.
import board import neopixel from PIL import Image from adafruit_pixel_framebuf import PixelFramebuffer
After that, set up the object, except it's using D18 in this case. You can find more details about this earlier in this guide.
pixel_pin = board.D18
pixel_width = 16
pixel_height = 16
pixels = neopixel.NeoPixel(
pixel_pin, pixel_width * pixel_height, brightness=0.1, auto_write=False,
)
pixel_framebuf = PixelFramebuffer(pixels, pixel_width, pixel_height, reverse_x=True,)
Next use Pillow to create a background and alpha_composite() the image onto it. The reason to do it this way is because the adafruit_framebuf library requires the image to be in RGB format and if you directly you use convert() in Pillow, it will convert all transparencies to white. It's easier to see with a darker background.
Start off by creating a new image in RGBA mode. RGBA mode is required to use the alpha_composite() function. The default color is black, so you don't need to specify a color to use by default, although you certainly could.
image = Image.new("RGBA", (pixel_width, pixel_height))
Next open the icon file.
icon = Image.open("blinka_16x16.png")
Next use the alpha_composite() function to blend the icon onto the black background.
image.alpha_composite(icon)
Finally, convert the combined image to RGB right before passing it to the image() function and then display it.
pixel_framebuf.image(image.convert("RGB"))
pixel_framebuf.display()
That's it. It should display onto the NeoPixels.
Page last edited March 08, 2024
Text editor powered by tinymce.