diff --git a/include/gpio.h b/include/gpio.h index 2244c49..9103b52 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -44,10 +44,15 @@ class GPIO { if (!value) return; *gpio_set_bits_ = value; #ifdef RGB_SLOWDOWN_GPIO - *gpio_set_bits_ = value; -# if RGB_SLOWDOWN_GPIO > 1 +# if RGB_SLOWDOWN_GPIO != 0 + *gpio_set_bits_ = value; // Slowdown=1. Typical for RPi 2 & 3, not for 1. +# endif +# if RGB_SLOWDOWN_GPIO >= 2 *gpio_set_bits_ = value; // for really slow cases # endif +# if RGB_SLOWDOWN_GPIO >= 3 + *gpio_set_bits_ = value; // Jeez, that should really not be necessary +# endif #endif } @@ -56,10 +61,15 @@ class GPIO { if (!value) return; *gpio_clr_bits_ = value; #ifdef RGB_SLOWDOWN_GPIO - *gpio_clr_bits_ = value; -# if RGB_SLOWDOWN_GPIO > 1 +# if RGB_SLOWDOWN_GPIO != 0 + *gpio_clr_bits_ = value; // Slowdown=1. Typical for RPi 2 & 3, not for 1. +# endif +# if RGB_SLOWDOWN_GPIO >= 2 *gpio_clr_bits_ = value; // for really slow cases # endif +# if RGB_SLOWDOWN_GPIO >= 3 + *gpio_clr_bits_ = value; // Jeez, that should really not be necessary +# endif #endif } @@ -103,4 +113,5 @@ public: }; } // end namespace rgb_matrix + #endif // RPI_GPIO_H diff --git a/lib/Makefile b/lib/Makefile index 7b30648..7632362 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -20,7 +20,8 @@ TARGET=librgbmatrix # you happen to have gotten such panel. #DEFINES+=-DRGB_SWAP_GREEN_BLUE -# For curiosity reasons: uncomment to see refresh rate in terminal. +# For curiosity reasons and while tweaking values for LSB_PWM_NANOSECONDS, +# uncomment to see refresh rate in terminal. #DEFINES+=-DSHOW_REFRESH_RATE # For low refresh rates below 100Hz (e.g. a lot of panels), the eye will notice @@ -29,21 +30,40 @@ TARGET=librgbmatrix #DEFINES+=-DRGB_SCAN_INTERLACED=1 # The signal can be too fast for some LED panels, in particular with newer -# (faster) Raspberry Pi 2s. -# In these cases, you want to make sure that -# - The cables are short enough from the GPIO header to the panel. -# - Maybe use an active level shifter and bus driver, for instance by building -# up one of the adapter-PCBs in the ../adapter/ directory or use -# the Adafruit HAT. The output drivers of the GPIO are not really good -# in driving long cables - this will improve the situation. +# (faster) Raspberry Pi 2s - in that case, the LED matrix only shows garbage. +# This allows to slow down the GPIO for these cases. # -# If the above fails or you can't implement them, try uncommenting the -# following line and recompile; it will slow down GPIO, but will as well reduce -# the frame-rate. -# Sometimes, you even have to give RGB_SLOWDOWN_GPIO=2 for particularly slow -# panels or bad signal cable situations. +# Set to 1 for RPi2 or RPi3 (default below), because they are typically +# faster than the panels can digest. +# +# Set to 0 (or comment out) for RPi1, that are slow enough. +# +# Sometimes, you even have to give RGB_SLOWDOWN_GPIO=2 or even 3 for +# particularly slow panels or bad signal cable situations. If that happens, you +# typically should double check cables and add TTL level converter if you +# haven't. DEFINES+=-DRGB_SLOWDOWN_GPIO=1 +# This allows to change the base time-unit for the on-time in the lowest +# significant bit in nanoseconds. +# Higher numbers provide better quality (more accurate color, less ghosting), +# but have a negative impact on the frame rate. +# +# For the same frame-rate, displays with higher multiplexing (e.g. 1:16 or 1:32) +# require lower values. +# +# Good values for full-color display (PWM=11) are somewhere between 100 and 300. +# +# If you you use reduced bit color (e.g. PWM=1 for 8 colors like for text), +# then higher values might be good to minimize ghosting (and you can afford +# that, because lower PWM values result in higher frame-rates). +# +# How to decide ? Just leave the default if things are fine. If you see +# ghosting in high-contrast applications (e.g. text), increase the value. +# If you want to tweak, watch the framerate (-DSHOW_FRAME_RATE) while playing +# with this number and the PWM values. +#DEFINES+=-DLSB_PWM_NANOSECONDS=130 + # ------------ Pinout options; usually no change needed here -------------- # Uncomment the following line for Adafruit Matrix HAT gpio mappings. @@ -93,6 +113,10 @@ DEFINES+=-DRGB_SLOWDOWN_GPIO=1 # Experimental. Only use this if you do 1 bit PWM. #DEFINES+=-DEXPERIMENTAL_HIGH_BRIGHTNESS +# If someone gives additional values on the make commandline e.g. +# make USER_DEFINES="-DSHOW_REFRESH_RATE" +DEFINES+=$(USER_DEFINES) + INCDIR=../include CXXFLAGS=-Wall -O3 -g -fPIC $(DEFINES) diff --git a/lib/framebuffer.cc b/lib/framebuffer.cc index 3bba157..f1b7592 100644 --- a/lib/framebuffer.cc +++ b/lib/framebuffer.cc @@ -33,9 +33,18 @@ enum { kBitPlanes = 11 // maximum usable bitplanes. }; -// Lower values create a higher framerate, but display will be a -// bit dimmer. Good values are between 100 and 200. +#if defined(LSB_PWM_NANOSECONDS) +// Make sure that there are sensible values. +// > 3000ns flickers even with 1:4 multiplexing on a single panel +// < 50ns timings don't really work well with the TTL-logic on the matrix. +# if (LSB_PWM_NANOSECONDS >= 50) && (LSB_PWM_NANOSECONDS <= 3000) +static const long kBaseTimeNanos = LSB_PWM_NANOSECONDS; +# else +# error "PWM Nanoseconds should be in the range of 50...3000" +# endif +#else static const long kBaseTimeNanos = 130; +#endif // We need one global instance of a timing correct pulser. There are different // implementations depending on the context. @@ -373,8 +382,6 @@ void Framebuffer::DumpToMatrix(GPIO *io) { row_address.bits.d = d_row >> 3; row_address.bits.e = d_row >> 4; - io->WriteMaskedBits(row_address.raw, row_mask.raw); // Set row address - // Rows can't be switched very quickly without ghosting, so we do the // full PWM of one row before switching rows. for (int b = kBitPlanes - pwm_to_show; b < kBitPlanes; ++b) { @@ -391,13 +398,14 @@ void Framebuffer::DumpToMatrix(GPIO *io) { // OE of the previous row-data must be finished before strobe. sOutputEnablePulser->WaitPulseFinished(); + // Setting address and strobing needs to happen in dark time. + io->WriteMaskedBits(row_address.raw, row_mask.raw); // Set row address io->SetBits(strobe.raw); // Strobe in the previously clocked in row. io->ClearBits(strobe.raw); // Now switch on for the sleep time necessary for that bit-plane. sOutputEnablePulser->SendPulse(b); } - sOutputEnablePulser->WaitPulseFinished(); } } } // namespace internal diff --git a/lib/gpio.cc b/lib/gpio.cc index 0243588..ed0b8fb 100644 --- a/lib/gpio.cc +++ b/lib/gpio.cc @@ -456,5 +456,4 @@ PinPulser *PinPulser::Create(GPIO *io, uint32_t gpio_mask, } #endif } - } // namespace rgb_matrix