9 flickering and brightness issue#10
Open
nishil-26 wants to merge 12 commits into
Open
Conversation
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.
Fix pixel drawing logic to mirror Y coordinate and adjust X coordinate correctly.
…Scroll_Cylinder.ino.ino
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
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.
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.
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.
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.