The repository contains the WS2812 Encoder, an MPLAB® X project which uses Core Independent Peripherals (CIPs) by following the interaction between the Custom Logic Block (CLB), Direct Memory Access Controller (DMA) and Timer0 (TMR0) to achieve a CPU-less data processing architecture.
The CLB peripheral is a collection of logic elements that can be programmed to perform a wide variety of digital logic functions. The logic function may be completely combinatorial, sequential, or a combination of the two, enabling users to incorporate hardware-based custom logic into the applications.
More details and code examples on the PIC18F56Q35 can be found at the following links:
- PIC18F56Q35 Product Page
- PIC18F56Q35 Code Examples on Discover
- PIC18F56Q35 Code Examples on GitHub
- WS2818 Data Sheet
- SPI to WS2812 — Use Case for CLB Using the PIC16F13276 Microcontroller With MCC Melody
- MPLAB® X IDE v6.30 or newer or MPLAB® Tools for VS Code®
- MPLAB® XC8 v3.10 or newer
- PIC18F-Q_DFP v1.30.487 or newer
-
The PIC18F56Q35 Curiosity Nano Development board is used as a test platform:

-
Logic Analyzer
To program the Curiosity Nano board with this MPLAB X project, follow the steps provided in the How to Program the Curiosity Nano Board chapter.
This project is an implementation of a WS2812 encoder using CIPs by following the interaction between CLB, DMA and TMR0 to achieve a CPU-less operation. The raw data is streamed via DMA directly into the CLB, where it is encoded using a hardware-defined digital logic circuit. The timing of the encoding process is provided by TMR0, acting as the bit period clock, while the CPU is not involved in the data path. The encoded signal is then generated on a single output line. The CLB circuit is captured in the figure below:
The design includes a Parallel-In Serial-Out (PISO) shift register used to serialize the input data loaded via the 8-bit long CLB Software Input Low Register (CLBINL), that can be used as destination for the DMA controller. The logic is driven by the TMR0 overflow signal acting as the bit clock.
The serialized data is further processed by the WS2812B encoder block, which generates the final encoded output. Control signals, such as Encoder Enable, manage the data flow, while status signals (ACTIVE, RDY) indicate transfer activity. The entire data path is hardware-driven, with data supplied via DMA and no CPU intervention required.
The raw data is driven by the DMA controller, which transfers data directly from various memory sources such as Flash, EEPROM, Special Function Registers (SFR) or General Purpose Registers (GPR). This data is then used as input for the CLB-based PISO block, which generates a serialized WS2812 data signal synchronized with the clock provided by TMR0. These signals are further processed by the logic implemented inside the CLB peripheral, which outputs the WS2812 encoded signal.
The data is transferred by the DMA controller from a predefined memory source and streamed into the CLB input path. The DMA operates autonomously, feeding data byte by byte into the hardware logic without CPU intervention, following a predefined transfer sequence.
The DMA transfer is triggered by the CLB_IRQ0 signal, ensuring synchronization between the CLB logic and the incoming data stream. This trigger is asserted either by the RDY signal generated by the PISO module, indicating that new data can be loaded, or by a software-controlled mechanism. The trigger occurs when a logic 1 is written to bit 0 of the CLBINH register, provided that the write operation is validated by the Write Pulse status from the CLBINHWR input option of the CLB.
The CLBOUTL0 output is used as the final WS2812 encoded signal. The CLBOUTL1, CLBOUTL2 and CLBOUTL3 outputs are used for real-time debugging by routing internal PISO signals to external pins via the Peripheral Pin Select (PPS) module, allowing direct observation of the data path.
In this implementation, the WS2812 signal is controlled by adjusting the TMR0 period, which defines the duration of each bit transfer. To power up an LED, a "1 code" signal must be transmitted, meaning a Pulse-Width Modulation (PWM) signal with 0.7 μs ± 150 ns high and 0.6 μs ± 150 ns low periods. To power-off, a "0 code" signal will be transmitted, meaning a PWM signal with 0.35 μs ± 150 ns high and 0.8 μs ± 150 ns low periods. For this example, the "1 code" signal is described by twelve high signal cycles, 1 logic, and four low signal cycles, 0 logic, and the "0 code" is composed of six high signal cycles and ten low signal cycles. Each transmitted byte describes sixteen cycles.
The ENC_DIN signal is used as the data input for the WS2812 encoding logic. This signal is latched and used to select between two predefined timing patterns stored in the LUTs. Depending on whether the input bit is 0 or 1, the corresponding LUT generates the appropriate waveform segment. The multiplexer then selects the correct sequence, which is forwarded to the output stage. For a better understanding of the above information, the diagram below presents the sequence charts and timings.
Note: The timer frequency must be configured at twice the desired WS2812 frequency, as each bit period requires two timing intervals for correct encoding in the CLB design.
The following peripheral and clock configurations are set up using the MPLAB Code Configurator (MCC) Melody for the PIC18F56Q35:
-
Configuration Bits:
-
Clock Control:
-
CLB Synthesizer Library:
-
CRC:
- Auto-configured by CLB
-
TMR0:
-
DMA1:
- DMA Enable: Enabled
- Start Trigger: CLB0
- Abort Trigger: DMA1SCNT
- Abort Trigger Enable: Enabled
- Source Region: Program Flash
- Source Address: 0
- Source Mode: incremented
- Source Message Size: 1
- Destination Region: SFR
- Destination Module: CLB1
- Destination SFR: CLBSWINL
- Destination Mode: Unchanged
- Destination Message Size: 1

-
Pin Grid View and Pins:
Two patterns are saved in the image.h header file called imageR and imageG constants. Those variables help display the CLB acronym in two different colors, red and green, as shown in the demo below. Only two wires are needed between the microcontroller and the WS2812 - the output pin from the CLB (RD4) and the ground (GND).
Note: The WS2812 matrix must be externally powered up due to a higher power consumption.
The logic analyzer captures illustrate the correct operation of the WS2812 hardware encoder implemented using CLB and DMA. The PISO signals show the serialized data flow and timing reference, while the final output (WS2812 OUT) represents the encoded WS2812 waveform. A continuous data stream is observed during the active transmission period, confirming proper DMA operation.
At the bit level, two distinct pulse widths can be identified, corresponding to logic ‘0’ and logic ‘1’. The overall bit period remains constant (~1.25 µs), validating compliance with the WS2812 protocol. These results confirm stable, CPU-independent signal generation.
This example demonstrates the capabilities of the CLB, a CIP, to implement a fully hardware-based WS2812 encoder. The design leverages DMA-driven data transfers and timer-controlled timing, eliminating CPU involvement in the data path while enabling efficient and deterministic signal encoding.
This chapter demonstrates how to use the MPLAB X IDE to program a PIC® device with an Example_Project.X. This is applicable to other projects.
-
Connect the board to the PC.
-
Open the
Example_Project.Xproject in MPLAB X IDE. -
Set the
Example_Project.Xproject as main project.
Right click the project in the Projects tab and click Set as Main Project.
-
Clean and build the
Example_Project.Xproject.
Right click theExample_Project.Xproject and select Clean and Build.
-
Select PICxxxxx Curiosity Nano in the Connected Hardware Tool section of the project settings:
Right click the project and click Properties.
Click the arrow under the Connected Hardware Tool.
Select PICxxxxx Curiosity Nano (click the SN), click Apply and then click OK:
-
Program the project to the board.
Right click the project and click Make and Program Device or directly press the specific button.












