{"id":26953210,"url":"https://github.com/jupfu/hub75","last_synced_at":"2025-06-25T07:34:17.913Z","repository":{"id":285292352,"uuid":"957634317","full_name":"JuPfu/hub75","owner":"JuPfu","description":"Hub75 LED matrix panel driver for Raspberry Pi Pico ","archived":false,"fork":false,"pushed_at":"2025-05-24T17:36:52.000Z","size":5364,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-24T18:35:35.753Z","etag":null,"topics":["c","c-sdk","dma","hub75","led-matrix-displays","pico","pio","raspberry-pi-pico"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JuPfu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-30T20:42:11.000Z","updated_at":"2025-05-24T17:36:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"d36e0c07-bb5b-4179-8ec7-e8e1dc84f334","html_url":"https://github.com/JuPfu/hub75","commit_stats":null,"previous_names":["jupfu/hub75"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JuPfu/hub75","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuPfu%2Fhub75","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuPfu%2Fhub75/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuPfu%2Fhub75/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuPfu%2Fhub75/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuPfu","download_url":"https://codeload.github.com/JuPfu/hub75/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuPfu%2Fhub75/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261827441,"owners_count":23215749,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c-sdk","dma","hub75","led-matrix-displays","pico","pio","raspberry-pi-pico"],"created_at":"2025-04-03T01:29:16.381Z","updated_at":"2025-06-25T07:34:17.904Z","avatar_url":"https://github.com/JuPfu.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HUB75 DMA-Based Driver\n\n\nhttps://github.com/user-attachments/assets/7c41193c-c724-4fae-8823-af36d70fcedd\n\n*Demo video: Colours are much brighter and more brilliant in reality*\n\n## Documentation and References\n\nThis project is based on:\n- [Raspberry Pi's pico-examples/pio/hub75](https://github.com/raspberrypi/pico-examples)\n- [Pimoroni's HUB75 driver](https://github.com/pimoroni/pimoroni-pico/tree/main/drivers/hub75)\n\nTo understand how RGB matrix panels work, refer to the article **[Everything You Didn't Want to Know About RGB Matrix Panels](https://learn.adafruit.com/adafruit-gfx-graphics-library/what-is-the-gfx-library)**. \nFor details on Binary Coded Modulation (BCM), see **[LED Dimming Using Binary Code Modulation](https://www.ti.com/lit/an/slva377a/slva377a.pdf)**.\n\n---\n## Achievements of the Revised Driver\n\nThe modifications to the Pimoroni HUB75 driver result in the following improvements:\n\n- **Offloading Work**: Moves processing from the CPU to DMA and PIO co-processors.\n- **Performance Boost**: Implements self-paced, interlinked DMA and PIO processes.\n- **Eliminates Synchronization Delays**: No need for `hub75_wait_tx_stall`, removing blocking synchronization.\n- **Optimized Interrupt Handling**: Reduces code complexity in the interrupt handler.\n\nThese enhancements lead to significant performance improvements. In tests up to a **250 MHz system clock**, no ghost images were observed.\n\n---\n## Motivation\n\nAs part of a private project, I sought to gain deeper knowledge of the Raspberry Pi Pico microcontroller. I highly recommend **[Raspberry Pi Pico Lectures 2022 by Hunter Adams](https://youtu.be/CAMTBzPd-WI?feature=shared)**—they provide excellent insights! \n\nIf you are specifically interested in **PIO (Programmable Input/Output)**, start with [Lecture 14: Introducing PIO](https://youtu.be/BVdaw56Ln8s?feature=shared) and [Lecture 15: PIO Overview and Examples](https://youtu.be/wet9CYpKZOQ).\n\nInspired by Adams' discussion on **[DMA](https://youtu.be/TGjUHChO1kM?feature=shared\u0026t=1475) and PIO co-processors**, I optimized the HUB75 driver as a self-assigned challenge.\n\n😊 **[Raspberry Pi Pico Lectures 2025 by Hunter Adams](https://youtu.be/a4uLrfqHZQU?feature=shared\")** is available now!\n\n---\n## Evolution of Pico HUB75 Drivers\n\n### Raspberry Pi Pico HUB75 Example\n\nThe **Pico HUB75 example** demonstrates connecting an **HUB75 LED matrix panel** using PIO. This educational example prioritizes clarity and ease of understanding.\n\n- The color palette is generated by modulating the **Output Enable (OE)** signal.\n- **Binary Coded Modulation (BCM)** is applied row-by-row, modulating all color bits before advancing to the next row.\n- Synchronization depends on `hub75_wait_tx_stall`.\n- **No DMA is used**, leading to lower performance.\n\n### Pimoroni HUB75 Driver\n\nThe **Pimoroni HUB75 driver** improves performance by:\n- Switching from **row-wise** to **plane-wise** modulation handling.\n- Using **DMA** to transfer pixel data to the PIO state machine.\n- Still relying on `hub75_wait_tx_stall` for synchronization.\n\n![hub_pimoroni](assets/pimoroni_dma.png)\n\n*Picture 1: Pimoroni's Hub75 Driver DMA Section*\n\n---\n## Eliminating `hub75_wait_tx_stall`\n\nBoth the **Raspberry Pi and Pimoroni** implementations use `hub75_wait_tx_stall`, which ensures:\n- The state machine **stalls** on an empty TX FIFO.\n- The system **waits** until the OEn pulse has finished.\n\nHowever, this blocking method **prevents an efficient DMA-based approach**.\n\n### Original `hub75_wait_tx_stall` Implementation\n```c\nstatic inline void hub75_wait_tx_stall(PIO pio, uint sm) {\n    uint32_t txstall_mask = 1u \u003c\u003c (PIO_FDEBUG_TXSTALL_LSB + sm);\n    pio-\u003efdebug = txstall_mask;\n    while (!(pio-\u003efdebug \u0026 txstall_mask)) {\n        tight_loop_contents();\n    }\n}\n```\n### Alternative Approach\nInstead of waiting for TX FIFO stalling, we can:\n1. Modify the **PIO program** to emit a signal once the OEn pulse completes.\n2. Set up a **DMA channel** to listen for this signal.\n3. Establish an **interrupt handler** to trigger once the signal is received.\n\nThis approach allows fully **chained DMA execution** without CPU intervention.\n\n\u003cimg src=\"assets/hub75_row.png\" width=\"360\" height=\"186\"\u003e\n\n*Picture 2: Modified hub75_row Program*\n\n---\n## DMA Chains and PIO State Machines in the Revised HUB75 Driver\n\n### Overview\n\nThe following diagram illustrates the interactions between **DMA channels** and **PIO state machines**:\n\n```\n[ Pixel Data DMA ] -\u003e [ hub75_data_rgb888 PIO ]\n       |\n       |--\u003e [ Dummy Pixel Data DMA ] -\u003e [ hub75_data_rgb888 PIO ]\n                  |\n                  |--\u003e [ OEn Data DMA ] -\u003e [ hub75_row PIO ]\n                           |\n                           |--\u003e [ OEn Finished DMA ] (Triggers interrupt)\n```\n### Step-by-Step Breakdown\n\n1. **Pixel Data Transfer**\n   - Pixel data is streamed via **DMA** to the **hub75_rdata_gb888** PIO state machine.\n   - This handles shifting pixel data into the LED matrix.\n\n2. **Dummy Pixel Handling**\n   - A secondary **dummy pixel DMA channel** adds additional pixel data.\n   - This ensures correct clocking of the final piece of genuine data.\n\n3. **OEn Pulse Generation**\n   - The **OEn data DMA channel** sends 32-bit words - 5 bit address information (row select) and 27 bit puls width - to the **hub75_row** PIO state machine.\n   - This output enable signal switches on those LEDs in the current row with bit set in the current bitplane for the specified number of cycles.\n\n4. **Interrupt-Driven Synchronization**\n   - A final **OEn finished DMA channel** listens for the end of the pulse.\n   - An **interrupt handler** (`oen_finished_handler`) resets DMA for the next cycle.\n\n\n![hub75_dma](assets/hub75_dma.png)\n\n*Picture 3: Chained DMA Channels and assigned PIOs*\n\n---\n### Refresh Rate Performance\n\nWith a **bit-depth of 10**, the HUB75 driver achieves the following refresh rates for a 64 x 64 matrix depending on the system clock:\n\n| System Clock | Refresh Rate |\n|--------------|---------------|\n| 100 MHz      | 179 Hz        |\n| 150 MHz      | 268 Hz        |\n| 200 MHz      | 358 Hz        |\n| 250 MHz      | 448 Hz        |\n\nThese results demonstrate stable operation and high-performance display rendering across a wide range of system clocks.\n\n### Key Benefits of this Approach\n✅ Fully **automated** data transfer using **chained DMA channels**.\n\n✅ Eliminates **CPU-intensive** busy-waiting (`hub75_wait_tx_stall`).\n\n✅ Ensures **precise timing** without unnecessary stalling.\n\n---\n## Conclusion\n\nBy offloading tasks to **DMA and PIO**, the revised HUB75 driver achieves **higher performance**, **simpler interrupt handling**, and **better synchronization**. This approach significantly reduces CPU overhead while eliminating artifacts like **ghosting** at high clock speeds.\n\nIf you're interested in optimizing **RGB matrix panel drivers**, this implementation serves as a valuable reference for efficient DMA-based rendering.\n\n---\n\n## Demo Effects\n\n⚠️ The examples contained in hub75_lvgl.cpp have been tested with a Raspberry Pi Pico 2 microcontroller (RP2350). For a RP2040 processor you might have to comment out some demo effects due to minor memory capabilities. Ask if you need support 🙂.\n\n## How to Use This Project in VSCode\n\nYou can easily use this project with VSCode, especially with the **Raspberry Pi Pico plugin** installed. Follow these steps:\n\n1. **Open VSCode and start a new window**.\n2. **Clone the repository**:\n   - Press `Ctrl+Shift+P` and select `Git: Clone`.\n   - Paste the URL: `https://github.com/JuPfu/hub75`\n\n      \u003cimg src=\"assets/VSCode_1.png\" width=\"460\" height=\"116\"\u003e\n\n   - Choose a local directory to clone the repository into.\n\n      \u003cimg src=\"assets/VSCode_2.png\" width=\"603\" height=\"400\"\u003e \n\n\n3. **Project Import Prompt**:\n   - Consent to open the project.\n\n      \u003cimg src=\"assets/VSCode_3.png\" width=\"603\" height=\"400\"\u003e \n\n   - When prompted, \"Do you want to import this project as Raspberry Pi Pico project?\", click **Yes** or wait a few seconds until the dialog prompt disappears by itself.\n\n4. **Configure Pico SDK Settings**:\n   - A settings page will open automatically.\n   - Use the default settings unless you have a specific setup.\n\n      \u003cimg src=\"assets/VSCode_4.png\" width=\"603\" height=\"400\"\u003e \n\n   - Click **Import** to finalize project setup.\n   - Switch the board-type to your Pico model.\n\n      \u003cimg src=\"assets/VSCode_5.png\" width=\"599\" height=\"415\"\u003e \n\n5. **Wait for Setup Completion**:\n   - VSCode will download required tools, the Pico SDK, and any plugins.\n\n6. **Connect the Hardware**:\n   - Make sure the HUB75 LED matrix is properly connected to the Raspberry Pi Pico.\n   - Attach the Rasberry Pi Pico USB cable to your computer\n\n7. **Build and Upload**:\n   - Compiling the project can be done without a Pico attached to the computer.\n\n      \u003cimg src=\"assets/VSCode_6.png\" width=\"600\" height=\"416\"\u003e \n\n   - Click the **Run** button in the bottom taskbar.\n   - VSCode will compile and upload the firmware to your Pico board.\n\n\u003e 💡 If everything is set up correctly, your matrix should come to life with the updated HUB75 DMA driver.\n\n---\n\n## Next Steps\n\n- **Add another chained DMA channel** to further reduce calls to the oen_finished_handler, trading memory for reduced CPU load.\n\n- **Investigate removing the hub75_data_rgb888_set_shift method**, potentially achieving a completely DMA- and PIO-based solution with no CPU involvement.\n\nFor any questions or discussions, feel free to contribute or open an issue!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjupfu%2Fhub75","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjupfu%2Fhub75","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjupfu%2Fhub75/lists"}