Skip to content

PeterParker/unicorn-hat

Repository files navigation

unicorn-hat

Built with Claude Code

A Rust library for controlling the Pimoroni Unicorn HAT (8x8 LED matrix) on Raspberry Pi.

Note: This project was developed using Claude Code.

Project Structure

This repository is organized as a Cargo workspace:

  • unicorn-hat/ - Core library for hardware control and drawing primitives
  • unicorn-hat-extras/ - High-level convenience features (fonts, text scrolling, animations)

Most users will want to use the core unicorn-hat crate. The unicorn-hat-extras crate provides optional high-level features like text rendering and scrolling animations.

Features

Core Library (unicorn-hat)

  • Coordinate-based pixel control (x, y) and raw index access
  • RGB and HSV color models with conversion
  • Display rotation (0°, 90°, 180°, 270°)
  • Brightness control (0-255)
  • Drawing primitives (lines, rectangles)
  • Gradients (horizontal, vertical)
  • Color palettes and value-to-color mapping
  • Hardware abstraction (BGR format and zigzag mapping handled internally)

Extras Library (unicorn-hat-extras)

  • Bitmap font rendering (5×5 font for small displays)
  • Text rendering with automatic clipping
  • Scrolling text (4 directions: left, right, up, down)
  • Frame buffers for double-buffering and smooth animations
  • Ticker-tape and notification effects

Hardware Requirements

  • Pimoroni Unicorn HAT (8x8, NOT the HD version)
  • Raspberry Pi (any model with 40-pin GPIO header)
  • Root/sudo privileges or CAP_SYS_RAWIO capability (see Permissions section)

System Dependencies

Install required development libraries:

sudo apt-get update
sudo apt-get install -y libclang-dev llvm-dev

Enable SPI (if not already enabled):

sudo raspi-config
# Navigate to: Interface Options -> SPI -> Enable

Installation

Add to your Cargo.toml:

[dependencies]
unicorn-hat = "0.1"

For high-level features (text rendering, scrolling, frame buffers), also add:

[dependencies]
unicorn-hat = "0.1"
unicorn-hat-extras = "0.1"

Quick Start

use unicorn_hat::{UnicornHat, RGB8};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the HAT
    let mut hat = UnicornHat::new()?;

    // Set some pixels
    hat.set_pixel(0, 0, RGB8::RED)?;
    hat.set_pixel(7, 0, RGB8::GREEN)?;
    hat.set_pixel(0, 7, RGB8::BLUE)?;
    hat.set_pixel(7, 7, RGB8::YELLOW)?;

    // Display changes
    hat.display()?;

    Ok(())
}

Run with sudo:

sudo cargo run

Usage Examples

Rainbow Using HSV

use unicorn_hat::{UnicornHat, HSV};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut hat = UnicornHat::new()?;

    // Create a rainbow gradient
    for x in 0..8 {
        let hue = (x as f32 / 8.0) * 360.0;
        let hsv = HSV::new(hue, 1.0, 1.0);
        let rgb = hsv.into();

        for y in 0..8 {
            hat.set_pixel(x, y, rgb)?;
        }
    }

    hat.display()?;
    Ok(())
}

Brightness Control

use unicorn_hat::{UnicornHat, RGB8};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut hat = UnicornHat::new()?;

    // Fill with white
    hat.fill(RGB8::WHITE);

    // Set brightness to 25%
    hat.set_brightness(64);

    hat.display()?;
    Ok(())
}

Display Rotation

use unicorn_hat::{UnicornHat, Rotate, RGB8};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut hat = UnicornHat::new()?;

    // Rotate display 90° clockwise
    hat.set_rotation(Rotate::RotCW90);

    // Set top-left corner (logical coordinates)
    hat.set_pixel(0, 0, RGB8::RED)?;

    hat.display()?;
    Ok(())
}

Hex Colors

use unicorn_hat::{UnicornHat, RGB8};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut hat = UnicornHat::new()?;

    // Use web-style hex colors
    hat.fill(RGB8::from_hex(0xFF69B4));  // Hot pink

    hat.display()?;
    Ok(())
}

Example Programs

Core Library Examples

The unicorn-hat/examples/ directory contains several runnable programs:

  • simple.rs - Basic pixel control with colored corners
  • rainbow.rs - Animated HSV rainbow gradient
  • status_monitor.rs - Service health monitoring visualization
  • gradients.rs - Horizontal and vertical gradient demonstrations
  • drawing_demo.rs - Drawing primitives (lines, rectangles)

Additional hardware test and diagnostic examples are also available. See unicorn-hat/examples/README.md for the complete list.

Extras Library Examples

The unicorn-hat-extras/examples/ directory contains examples for high-level features:

  • double_buffer.rs - Frame buffer and double-buffering demonstration
  • ticker_tape.rs - Horizontal scrolling text (ticker-tape effects)
  • vertical_scroll.rs - Vertical scrolling text demonstrations

Run examples with:

sudo cargo run --example simple
sudo cargo run -p unicorn-hat-extras --example ticker_tape

Or from the workspace root with full package specification:

sudo cargo run -p unicorn-hat --example simple
sudo cargo run -p unicorn-hat-extras --example ticker_tape

API Overview

Core Types

  • UnicornHat - Main controller struct
  • RGB8 - 8-bit RGB color (0-255 per channel)
  • HSV - Hue/Saturation/Value color model
  • Rotate - Rotation modes (None, 90°, 180°, 270°)

Key Methods

// Initialization
let mut hat = UnicornHat::new()?;

// Pixel control
hat.set_pixel(x, y, color)?;        // Set by coordinate
hat.set_pixel_raw(index, color)?;   // Set by raw index
hat.get_pixel(x, y)?;                // Read pixel
hat.fill(color);                     // Fill all pixels
hat.clear();                         // Clear to black

// Display
hat.display()?;                      // Render to hardware

// Configuration
hat.set_brightness(128);             // 0-255 (default: 128)
hat.set_rotation(Rotate::RotCW90);   // Rotate display

// Bulk operations
hat.set_all(&grid)?;                 // Set from 2D array
let grid = hat.get_all()?;           // Read as 2D array

Color Constants

RGB8::BLACK, RGB8::WHITE, RGB8::RED, RGB8::GREEN, RGB8::BLUE,
RGB8::YELLOW, RGB8::CYAN, RGB8::MAGENTA, RGB8::ORANGE, RGB8::PURPLE

Coordinate System

(0,0) ──────────► (7,0)
  │                 │
  │     8x8 Grid    │
  │                 │
  ▼                 ▼
(0,7) ──────────► (7,7)
  • Origin (0,0) is top-left
  • X increases right (0-7)
  • Y increases down (0-7)
  • Rotation transforms coordinates before mapping to physical LEDs

Permissions

The library requires hardware access to control PWM for WS2812 LEDs. On Raspberry Pi, /dev/mem access requires special privileges.

Option 1: Run with sudo (recommended for development)

sudo cargo run

This is the simplest approach and works reliably during development.

Option 2: Set capabilities on release binaries (for production)

For production deployments, you can set capabilities on compiled binaries to avoid sudo:

  1. Build your program in release mode:

    cargo build --release
  2. Set the CAP_SYS_RAWIO capability:

    sudo setcap cap_sys_rawio=ep target/release/your-program
  3. Run without sudo:

    ./target/release/your-program

Important: Capabilities are tied to specific binaries. If you rebuild, you must set capabilities again.

Why sudo is needed

On Raspberry Pi, accessing /dev/mem requires:

  1. Read/write permissions (handled by udev rules + gpio group)
  2. The CAP_SYS_RAWIO capability (requires root or setcap)

During development, using sudo is simpler because cargo rebuilds binaries frequently, which clears capabilities. For production binaries that don't change, setting capabilities once is the better approach.

Note: The included 99-ws2812.rules file sets up /dev/mem group permissions, but capabilities must still be set per-binary.

Known Limitations

  • Audio Conflict: PWM on GPIO 18 conflicts with analog audio output (3.5mm jack). Use HDMI audio or USB audio instead.
  • Single Instance: Only one process can control the HAT at a time.
  • Brightness: Default brightness is 50% (128/255) for safety. Adjust as needed.

Hardware Details

This library has been tested and verified with the following configuration:

  • GPIO Pin: 18 (PWM)
  • DMA Channel: 10
  • LED Type: WS2812
  • LED Count: 64 (8×8)
  • Frequency: 800 kHz
  • Color Format: BGR (handled internally)
  • Pixel Mapping: Zigzag pattern (handled internally)

The library automatically handles the physical LED wiring pattern and BGR color format - you always work with logical coordinates and RGB colors.

Documentation

Generate and view the full API documentation:

cargo doc --no-deps --open

Testing

Automated Tests

cargo test

Runs unit tests, doc tests, and automated integration tests.

Hardware Tests

./scripts/test-hw.sh

Runs hardware integration tests. The script automatically handles building, setting capabilities, and running tests single-threaded.

First-time setup (optional, avoids password prompts):

sudo visudo
# Add: pp4 ALL=(root) NOPASSWD: /usr/sbin/setcap

See TESTING.md for details.

Example Programs

Run hardware verification examples:

cargo run --example core_test
cargo run --example rotation_test
cargo run --example color_test

(Use sudo prefix if permissions not configured)

License

MIT License - see LICENSE file for details.

References

Contributing

This library was developed for personal use but is shared in case it's useful to others.

Development

For details about the development process, architecture decisions, and testing strategy, see docs/DEVELOPMENT.md.

Acknowledgments

  • Built on the rs_ws281x crate for WS2812 LED control
  • Inspired by the official Python library from Pimoroni
  • Hardware testing confirmed pixel mapping and color format

Note: This library is specifically for the 8x8 Unicorn HAT. For the 16x16 Unicorn HAT HD, see unicorn-hat-hd-rs.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors