Skip to content

Commit

Permalink
Provide a way to fix he refresh rate to a predetermined value to allow
Browse files Browse the repository at this point in the history
masking faint flickers.

Addresses flicker observations mentioned in hzeller#556 hzeller#551 hzeller#276 hzeller#495 hzeller#483 hzeller#478 hzeller#467
  • Loading branch information
hzeller committed Mar 17, 2018
1 parent 9f98e15 commit 055e5a9
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 7 deletions.
32 changes: 32 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,38 @@ HARDWARE_DESC?=regular
# Use PixelMappers instead (include/pixel-mapper.h)
#DEFINES+=-DREMOVE_DEPRECATED_TRANSFORMERS

# --- EXPERIMENTAL --
# This allows to fix the refresh rate to a particular refresh time in
# microseconds.
#
# This can be used to mitigate some situations in which you have a rare
# faint flicker, which can happen due to hardware events (network access)
# or other situations such as other IO or heavy memory access by other
# processes (all of which seem to break the isolation we request from the
# kernel. You did set isolcpus=3 right ?)
# You trade a slightly slower refresh rate and display brightness for less
# visible flicker situations.
#
# For this to calibrate, run your program for a while with --led-show-refresh
# and watch the line that shows the refresh time and the maximum microseconds
# for a frame observed. The maximum number is updated whenever the frame
# refresh take a little bit longer. So wait a while until that value doesn't
# change anymore (at least a minute, so that you catch tasks that happen once
# a minute). Some value might read e.g.
# 204.6Hz max: 5133usec
# Now take this maximum value you see there (here: 5133) and put in
# this define (don't forget to remove the # in front).
#
# The refresh rate will now be adapted to always have this amount of time
# between frames, so faster refreshes will be slowed down, but the occasional
# delayed frame will fit into the time-window as well, thus reducing visible
# brightness fluctuations.
#
# You can play with value a little and reduce until you find a good balance
# between refresh rate (which is reduce the higher this value is) and
# flicker suppression (which is better with higher values).
#DEFINES+=-DFIXED_FRAME_MICROSECONDS=5000

# ---- Pinout options for hardware variants; usually no change needed here ----

# Uncomment if you want to use the Adafruit HAT with stable PWM timings.
Expand Down
5 changes: 5 additions & 0 deletions lib/gpio.cc
Original file line number Diff line number Diff line change
Expand Up @@ -572,4 +572,9 @@ PinPulser *PinPulser::Create(GPIO *io, uint32_t gpio_mask,
return new TimerBasedPinPulser(io, gpio_mask, nano_wait_spec);
}
}

uint32_t GetMicrosecondCounter() {
return timer1Mhz ? *timer1Mhz : 0;
}

} // namespace rgb_matrix
34 changes: 27 additions & 7 deletions lib/led-matrix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
#endif

namespace rgb_matrix {

// Get rolling over microsecond counter. Right now for experimental
// purposes declared here (defined in gpio.cc).
uint32_t GetMicrosecondCounter();

using namespace internal;

// Pump pixels to screen. Needs to be high priority real-time because jitter
Expand All @@ -66,11 +71,16 @@ class RGBMatrix::UpdateThread : public Thread {

virtual void Run() {
unsigned frame_count = 0;
uint32_t largest_time = 0;

// Let's start measure max time only after a we were running for a few
// seconds to not pick up start-up glitches.
static const int kHoldffTimeUs = 2000 * 1000;
uint32_t initial_holdoff_start = GetMicrosecondCounter();
bool max_measure_enabled = false;

while (running()) {
struct timeval start, end;
if (show_refresh_) {
gettimeofday(&start, NULL);
}
const uint32_t start_time_us = GetMicrosecondCounter();

current_frame_->framebuffer()->DumpToMatrix(io_);

Expand All @@ -92,11 +102,21 @@ class RGBMatrix::UpdateThread : public Thread {

++frame_count;

#ifdef FIXED_FRAME_MICROSECONDS
while ((GetMicrosecondCounter() - start_time_us) < (uint32_t)FIXED_FRAME_MICROSECONDS) {
// busy wait.
}
#endif
const uint32_t end_time_us = GetMicrosecondCounter();
if (show_refresh_) {
gettimeofday(&end, NULL);
int64_t usec = ((uint64_t)end.tv_sec * 1000000 + end.tv_usec)
- ((int64_t)start.tv_sec * 1000000 + start.tv_usec);
uint32_t usec = end_time_us - start_time_us;
printf("\b\b\b\b\b\b\b\b%6.1fHz", 1e6 / usec);
if (usec > largest_time && max_measure_enabled) {
largest_time = usec;
printf(" max: %uusec\b\b\b\b\b\b\b\b\b\b\b\b\b\b", largest_time);
} else {
max_measure_enabled = (end_time_us - initial_holdoff_start) > kHoldffTimeUs;
}
}
}
}
Expand Down

0 comments on commit 055e5a9

Please sign in to comment.