Skip to content

9 flickering and brightness issue#10

Open
nishil-26 wants to merge 12 commits into
mainfrom
9-flickering-and-brightness-issue
Open

9 flickering and brightness issue#10
nishil-26 wants to merge 12 commits into
mainfrom
9-flickering-and-brightness-issue

Conversation

@nishil-26

@nishil-26 nishil-26 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor
  1. The Initial Bottleneck (The Flicker Phase)
    We started by attempting to port standard Arduino-based RGB matrix libraries. The panels were functional, but the flicker was unbearable.

The Issue: The standard library relied on digitalWrite() to "bitbang" the HUB75 signal lines (R1, G1, B1, R2, G2, B2, CLK, LAT, OE, A, B, C).

The Root Cause: digitalWrite() is a "postal service" function—it checks pin states, performs safety lookups, and runs PWM checks before moving a single bit. Doing this for 51,200 pixels per frame meant the processor was bogged down. Our refresh rate dropped to a dismal ~15 FPS, causing the severe flickering.

  1. The Architecture Gap (Why ESP32 Worked & ARIES Struggled)
    We hit a wall comparing our setup to the standard "ESP32-HUB75-I2S-DMA" library.

ESP32/HUB75 Reality: The ESP32 utilizes a specialized I2S-DMA hardware block that automatically streams memory to the display pins in the background without CPU intervention.

ARIES v3.0 Reality: The THEJAS32 SoC is a RISC-V powerhouse, but it lacks that specific audio-DMA hardware block. We couldn't "cheat" with hardware, so we were forced to solve the speed issue through "brute force" software optimization.

  1. Failed Attempts
    Hardware Timer Lockout (The "Glowing Screen"): We tried to offload the refresh() to the built-in Hardware Timer.

The Failure: The display.refresh() call was taking ~3.5ms, but we set the timer interrupt to trigger every 2.5ms. The CPU got trapped in a permanent interrupt loop (ISR Starvation), never returning to the loop() to draw text. Result: A blank or glowing white screen.

The RISC-V Fence Issue: In our early attempts, the code would write to memory, but the display wouldn't react. We realized the RISC-V architecture requires a specific assembly instruction (asm volatile ("fence");) to force the processor to push the data out of the cache and onto the physical copper pins.

  1. The Breakthrough (The Custom Driver)
    We stopped using the Arduino IDE’s "safe" functions and went straight to the silicon.

Manufacturer SDK Analysis: We dove into the C-DAC manufacturer files (gpio.c, platform.h). We discovered that the processor required 16-bit writes to the GPIO registers and that the GPIO registers were memory-mapped to specific addresses (0x10080000UL for GPIO_0).

Bypassing digitalWrite(): We built a custom fastDigitalWrite engine. Instead of calling the slow Arduino function, our code calculates the exact 16-bit memory address for every pin during setup().

Single-Cycle Writes: In refresh(), we now write directly to the memory address. This takes 1 clock cycle compared to the ~50+ cycles required by standard Arduino code.

  1. Final Result
    By mapping the memory directly and using the manufacturer-specified fence instructions, we eliminated the overhead entirely. The display refresh rate is now stable and independent of the loop(), scrolling is butter-smooth, and the brightness is locked at the maximum potential of the THEJAS32 processor.

Status: The display is flicker-free, the scrolling is independent of the refresh.

nishil-26 added 2 commits June 3, 2026 21:29
1. The Initial Bottleneck (The Flicker Phase)
We started by attempting to port standard Arduino-based RGB matrix libraries. The panels were functional, but the flicker was unbearable.

The Issue: The standard library relied on digitalWrite() to "bitbang" the HUB75 signal lines (R1, G1, B1, R2, G2, B2, CLK, LAT, OE, A, B, C).

The Root Cause: digitalWrite() is a "postal service" function—it checks pin states, performs safety lookups, and runs PWM checks before moving a single bit. Doing this for 51,200 pixels per frame meant the processor was bogged down. Our refresh rate dropped to a dismal ~15 FPS, causing the severe flickering.

2. The Architecture Gap (Why ESP32 Worked & ARIES Struggled)
We hit a wall comparing our setup to the standard "ESP32-HUB75-I2S-DMA" library.

ESP32/HUB75 Reality: The ESP32 utilizes a specialized I2S-DMA hardware block that automatically streams memory to the display pins in the background without CPU intervention.

ARIES v3.0 Reality: The THEJAS32 SoC is a RISC-V powerhouse, but it lacks that specific audio-DMA hardware block. We couldn't "cheat" with hardware, so we were forced to solve the speed issue through "brute force" software optimization.

3. Failed Attempts 
Hardware Timer Lockout (The "Glowing Screen"): We tried to offload the refresh() to the built-in Hardware Timer.

The Failure: The display.refresh() call was taking ~3.5ms, but we set the timer interrupt to trigger every 2.5ms. The CPU got trapped in a permanent interrupt loop (ISR Starvation), never returning to the loop() to draw text. Result: A blank or glowing white screen.

The RISC-V Fence Issue: In our early attempts, the code would write to memory, but the display wouldn't react. We realized the RISC-V architecture requires a specific assembly instruction (__asm__ __volatile__ ("fence");) to force the processor to push the data out of the cache and onto the physical copper pins.

4. The Breakthrough (The Custom Driver)
We stopped using the Arduino IDE’s "safe" functions and went straight to the silicon.

Manufacturer SDK Analysis: We dove into the C-DAC manufacturer files (gpio.c, platform.h). We discovered that the processor required 16-bit writes to the GPIO registers and that the GPIO registers were memory-mapped to specific addresses (0x10080000UL for GPIO_0).

Bypassing digitalWrite(): We built a custom fastDigitalWrite engine. Instead of calling the slow Arduino function, our code calculates the exact 16-bit memory address for every pin during setup().

Single-Cycle Writes: In refresh(), we now write directly to the memory address. This takes 1 clock cycle compared to the ~50+ cycles required by standard Arduino code.

5. Final Result
By mapping the memory directly and using the manufacturer-specified fence instructions, we eliminated the overhead entirely. The display refresh rate is now stable and independent of the loop(), scrolling is butter-smooth, and the brightness is locked at the maximum potential of the THEJAS32 processor.

Status: The display is flicker-free, the scrolling is independent of the refresh.
@nishil-26 nishil-26 linked an issue Jun 3, 2026 that may be closed by this pull request
@nishil-26 nishil-26 marked this pull request as draft June 3, 2026 16:03
@nishil-26 nishil-26 self-assigned this Jun 3, 2026
@nishil-26 nishil-26 marked this pull request as ready for review June 3, 2026 16:04
@nishil-26 nishil-26 marked this pull request as draft June 3, 2026 16:04
@nishil-26 nishil-26 requested a review from mnwsth June 3, 2026 16:05
@nishil-26 nishil-26 marked this pull request as ready for review June 3, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flickering and Brightness issue Solved and Examples Added

1 participant