diff --git a/README.md b/README.md
index 52fc296..a2a0b58 100644
--- a/README.md
+++ b/README.md
@@ -84,8 +84,8 @@ This documentation is split into parts that help you through the process
*
[Wire up the matrix to your Pi](./wiring.md). This document describes what
goes where. You might also be interested in [breakout boards](./adapter)
- for that. If you have an [Adafruit HAT], necessary steps are
- [described below](#if-you-have-an-adafruit-hat)
+ for that. If you have an [Adafruit HAT], you can choose that with
+ a command line option [described below](#if-you-have-an-adafruit-hat)
* Run a demo. You find that in the
[examples-api-use/](./examples-api-use#running-some-demos) directory:
```
@@ -133,8 +133,22 @@ Some might need to be changed for your particular kind of panel.
Here is a little run-down of what these command-line flags do and when you'd
like to change them.
+First things first: if you have a different wiring than described in
+[wiring](./wiring.md), for instance if you have an Adafruit HAT, you can
+choose these here:
+
+```
+--led-gpio-mapping=: Name of GPIO mapping used. Default "regular"
+```
+
+This can have values such as
+ - `--led-gpio-mapping=regular` The standard mapping of this library, described in the [wiring](./wiring.md) page.
+ - `--led-gpio-mapping=adafruit-hat` standard Adafruit HAT or
+ - `--led-gpio-mapping=adafruit-hat-pwm` Adafruit HAT with the anti-flicker hardware mod [described below](#improving-flicker).
+
+The next most important flags describe the type and number of displays connected
+
```
-# These are the most important
--led-rows= : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain= : Number of daisy-chained panels. (Default: 1).
--led-parallel= : For A/B+ models or RPi2,3b: parallel chains. range=1..3 (Default: 1).
@@ -365,16 +379,19 @@ ready-made vs. single-chain tradeoff is worthwhile, then you might go for that
The Adafruit HAT uses this library but a modified pinout to support other
features on the HAT. So they forked this library and modified the pinout there.
However, that fork is _ancient_, so I strongly suggest to use this original
-library instead - which in the meantime also has a way to switch to their pinout.
+library instead. You can choose the Adafruit pinout with a command line flag.
-In this library here, you can choose the Adafruit HAT pinout by editing
-`lib/Makefile` and change `HARDWARE_DESC?=regular` to `HARDWARE_DESC=adafruit-hat`.
+Just pass the option `--led-gpio-mapping=adafruit-hat`.
-Alternatively, you can prefix the compilation call with this variable like so:
+If you want to have this the default whenever you start (or if you are using
+the Python library that does not support to set this at runtime yet), add the
+following setting in front of your compilation:
```
HARDWARE_DESC=adafruit-hat make
```
-Then re-compile and a display connected to the HAT should work.
+(alternatively, you can modify the `lib/Makefile` and change it there directly)
+Then re-compile and the new flag default is now `adafruit-hat`, so
+no need to set it on the command line.
### Improving flicker
@@ -384,14 +401,17 @@ following picture (click to enlarge):
-Then, uncomment the following line in the Makefile and recompile.
+Then, start your programs with `--led-gpio-mapping=adafruit-hat-pwm`.
+If you want to make this the default setting your program starts with, you can
+also manually choose this with
```
-#DEFINES+=-DADAFRUIT_RGBMATRIX_HAT_PWM
+HARDWARE_DESC=adafruit-hat-pwm make
```
+to get this as default setting.
-Reboot the Pi and you now should have less visible flicker. This essentially
-gives you the hardware pulses feature.
+Now you should have less visible flicker. This essentially
+switches on the hardware pulses feature for the Adafruit HAT.
### 64x64 with E-line on Adafruit HAT
There are LED panels that have 64x64 LEDs packed, but they need 5 address lines,
diff --git a/examples-api-use/README.md b/examples-api-use/README.md
index 8ee0512..bc8a3a4 100644
--- a/examples-api-use/README.md
+++ b/examples-api-use/README.md
@@ -17,6 +17,7 @@ Options:
in the middle in an U-arrangement to get more vertical space.
-R : Sets the rotation of matrix. Allowed: 0, 90, 180, 270. Default: 0.
-t : Run for these number of seconds, then exit.
+ --led-gpio-mapping= : Name of GPIO mapping used. Default "regular"
--led-rows= : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain= : Number of daisy-chained panels. (Default: 1).
--led-parallel= : For A/B+ models or RPi2,3b: parallel chains. range=1..3 (Default: 1).
@@ -86,6 +87,7 @@ using rgb_matrix::RGBMatrix;
int main(int argc, char **argv) {
// Set some defaults
RGBMatrix::Options my_defaults;
+ my_defaults.hardware_mapping = "regular"; // or e.g. "adafruit-hat" or "adafruit-hat-pwm"
my_defaults.chain_length = 3;
my_defaults.show_refresh_rate = true;
rgb_matrix::RuntimeOptions runtime_defaults;
diff --git a/examples-api-use/c-example.c b/examples-api-use/c-example.c
index b99d441..74bd088 100644
--- a/examples-api-use/c-example.c
+++ b/examples-api-use/c-example.c
@@ -5,6 +5,7 @@
*/
#include "led-matrix-c.h"
+#include
#include
#include
@@ -31,6 +32,10 @@ int main(int argc, char **argv) {
offscreen_canvas = led_matrix_create_offscreen_canvas(matrix);
led_canvas_get_size(offscreen_canvas, &width, &height);
+
+ fprintf(stderr, "Size: %dx%d. Hardware gpio mapping: %s\n",
+ width, height, options.hardware_mapping);
+
for (i = 0; i < 1000; ++i) {
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
diff --git a/examples-api-use/demo-main.cc b/examples-api-use/demo-main.cc
index 0796cee..5892bd9 100644
--- a/examples-api-use/demo-main.cc
+++ b/examples-api-use/demo-main.cc
@@ -1160,7 +1160,8 @@ int main(int argc, char *argv[]) {
matrix->ApplyStaticTransformer(RotateTransformer(rotation));
}
- printf("Size: %dx%d\n", matrix->width(), matrix->height());
+ printf("Size: %dx%d. Hardware gpio mapping: %s\n",
+ matrix->width(), matrix->height(), matrix_options.hardware_mapping);
Canvas *canvas = matrix;
diff --git a/examples-api-use/minimal-example.cc b/examples-api-use/minimal-example.cc
index 2f0ace9..930f2ef 100644
--- a/examples-api-use/minimal-example.cc
+++ b/examples-api-use/minimal-example.cc
@@ -45,6 +45,7 @@ static void DrawOnCanvas(Canvas *canvas) {
int main(int argc, char *argv[]) {
RGBMatrix::Options defaults;
+ defaults.hardware_mapping = "regular"; // or e.g. "adafruit-hat"
defaults.rows = 32;
defaults.chain_length = 1;
defaults.parallel = 1;
diff --git a/include/led-matrix-c.h b/include/led-matrix-c.h
index e999e6a..9f99adc 100644
--- a/include/led-matrix-c.h
+++ b/include/led-matrix-c.h
@@ -43,6 +43,12 @@ struct LedCanvas;
* should zero out this struct before setting anything.
*/
struct RGBLedMatrixOptions {
+ /*
+ * Name of the hardware mapping used. If passed NULL here, the default
+ * is used.
+ */
+ const char *hardware_mapping;
+
/* The "rows" are the number of rows supported by the display, so 32 or 16.
* Default: 32.
* Corresponding flag: --led-rows
diff --git a/include/led-matrix.h b/include/led-matrix.h
index 706e862..f4d3692 100644
--- a/include/led-matrix.h
+++ b/include/led-matrix.h
@@ -61,6 +61,9 @@ public:
// Returns 'true' if all options look good.
bool Validate(std::string *err) const;
+ // Name of the hardware mapping. Something like "regular" or "adafruit-hat"
+ const char *hardware_mapping;
+
// The "rows" are the number
// of rows supported by the display, so 32 or 16. Default: 32.
// Flag: --led-rows
diff --git a/lib/Makefile b/lib/Makefile
index 355f37f..e2d7ffa 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,13 +4,14 @@
# -lrgbmatrix
##
OBJECTS=gpio.o led-matrix.o options-initialize.o framebuffer.o \
- thread.o bdf-font.o graphics.o transformer.o led-matrix-c.o
+ thread.o bdf-font.o graphics.o transformer.o led-matrix-c.o \
+ hardware-mapping.o
TARGET=librgbmatrix
# There are several different pinouts for various breakout boards that uses
# this library. If you are using the described pinout in the toplevel README.md
# or the standard active-3 breakout board, then 'regular' is the one you'd like
-# to use (there is also a 'classic' one for an early form).
+# to use.
#
# Adafruit also made a breakout board, if you want to use that, choose
# 'adafruit-hat'
@@ -18,15 +19,17 @@ TARGET=librgbmatrix
# These are the choices
# regular # Following this project wiring and using these PCBs
# adafruit-hat # If you have a RGB matrix HAT from Adafruit
-# classic # Not really used anymore
+# adafruit-hat-pwm # If you have an Adafruit HAT with PWM hardware mod.
+# classic # (deprecated) Classic Pi1/2/. Not used anymore.
+# classic-pi1 # (deprecated) Classic pinout on Rasperry Pi 1
HARDWARE_DESC?=regular
###
# After you change any of the following DEFINES, make sure to 'make' again.
#
-# Note, all of these options that don't directly influence the hardware mapping
-# can now can be set programmatically and via command line flags as well.
-# So be prepared for these to be removed in this Makefile.
+# Note, all of these options can now can be set programmatically and
+# via command line flags as well. No real need to change them in the Makefile.
+# (So be prepared for these to be removed at some point)
###
# If you see that your display is inverse, you might have a matrix variant
@@ -105,12 +108,9 @@ HARDWARE_DESC?=regular
# connect GPIO 4 (old OE) with 18 (the new OE); there are
# convenient solder holes labeled 4 and 18 on the Adafruit HAT, pretty
# close together.
-# Then uncomment the following define and recompile.
-#DEFINES+=-DADAFRUIT_RGBMATRIX_HAT_PWM
-
-# If you use HARDWARE_DESC=classic and a Raspberry Pi 1, Revision A,
-# this might be useful (untested).
-#DEFINES+=-DPI_REV1_RGB_PINOUT
+# Then you can set the flag --led-gpio-mapping=adafruit-hat-pwm
+# .. or uncomment the following line.
+#HARDWARE_DESC=adafruit-hat-pwm
# Typically, a Hub75 panel is split in two half displays, so that a 1:16
# multiplexing actually multiplexes over two half displays and gives 32 lines.
@@ -125,8 +125,10 @@ HARDWARE_DESC?=regular
# make USER_DEFINES="-DSHOW_REFRESH_RATE"
DEFINES+=$(USER_DEFINES)
+DEFINES+=-DDEFAULT_HARDWARE='"$(HARDWARE_DESC)"'
INCDIR=../include
-CXXFLAGS=-Wall -O3 -g -fPIC $(DEFINES) -Ihardware/$(HARDWARE_DESC)
+CFLAGS=-Wall -O3 -g -fPIC $(DEFINES)
+CXXFLAGS=$(CFLAGS)
all : $(TARGET).a $(TARGET).so.1
@@ -144,11 +146,13 @@ graphics.o: graphics.cc utf8-internal.h
%.o : %.cc compiler-flags
$(CXX) -I$(INCDIR) $(CXXFLAGS) -c -o $@ $<
+%.o : %.c compiler-flags
+ $(CC) -I$(INCDIR) $(CXXFLAGS) -c -o $@ $<
+
clean:
rm -f $(OBJECTS) $(TARGET).a $(TARGET).so.1
compiler-flags: FORCE
- @if [ ! -d hardware/$(HARDWARE_DESC) ] ; then echo "HARDWARE_DESC='$(HARDWARE_DESC)' is an unsupported hardware description. Typo ?"; exit 1; fi
@echo '$(CXX) $(CXXFLAGS)' | cmp -s - $@ || echo '$(CXX) $(CXXFLAGS)' > $@
.PHONY: FORCE
diff --git a/lib/framebuffer-internal.h b/lib/framebuffer-internal.h
index 47b674f..df98b07 100644
--- a/lib/framebuffer-internal.h
+++ b/lib/framebuffer-internal.h
@@ -17,6 +17,8 @@
#include
+#include "hardware-mapping.h"
+
namespace rgb_matrix {
class GPIO;
class PinPulser;
@@ -64,6 +66,7 @@ public:
~Framebuffer();
// Initialize GPIO bits for output. Only call once.
+ static void InitHardwareMapping(const char *named_hardware);
static void InitGPIO(GPIO *io, int rows, int parallel,
bool allow_hardware_pulsing,
int pwm_lsb_nanoseconds);
@@ -96,9 +99,7 @@ public:
void Fill(uint8_t red, uint8_t green, uint8_t blue);
private:
- // Define the type to do the pin-mapping. These are include fils
- // found in include directory hardware/$(name-of-mapping)
-#include "led-panel-pin-mapping.h" // see HARDWARE_DESC in lib/Makefile
+ static const struct HardwareMapping *hardware_mapping_;
void InitDefaultDesignator(int x, int y, PixelDesignator *designator);
inline void MapColors(uint8_t r, uint8_t g, uint8_t b,
@@ -125,11 +126,8 @@ private:
// Each bitplane-column is pre-filled IoBits, of which the colors are set.
// Of course, that means that we store unrelated bits in the frame-buffer,
// but it allows easy access in the critical section.
- IoBits *bitplane_buffer_;
- inline IoBits *ValueAt(int double_row, int column, int bit);
- inline IoBits &color_bits(uint32_t *val) {
- return *reinterpret_cast(val);
- }
+ gpio_bits_t *bitplane_buffer_;
+ inline gpio_bits_t *ValueAt(int double_row, int column, int bit);
PixelMapper **shared_mapper_; // Storage in RGBMatrix.
};
diff --git a/lib/framebuffer.cc b/lib/framebuffer.cc
index 67adee8..394c6e5 100644
--- a/lib/framebuffer.cc
+++ b/lib/framebuffer.cc
@@ -19,11 +19,12 @@
#include "framebuffer-internal.h"
-#include
#include
-#include
-#include
#include
+#include
+#include
+#include
+#include
#include "gpio.h"
@@ -33,22 +34,6 @@ enum {
kBitPlanes = 11 // maximum usable bitplanes.
};
-// Leave this in here for a while.
-#if defined(ADAFRUIT_RGBMATRIX_HAT) && !FYI_ADAFRUIT_HAT_PIN_MAPPING_INCLUDED_
-# error "You are using an old way to select the Adafruit HAT."
-# error "Set HARDWARE_DESC=adafruit-hat instead of ADAFRUIT_RGBMATRIX_HAT"
-# error "Check out https://github.com/hzeller/rpi-rgb-led-matrix#switch-the-pinout"
-#endif
-
-// Remind forgetful Makefile option editors
-#if defined(ADAFRUIT_RGBMATRIX_HAT_PWM) && !FYI_ADAFRUIT_HAT_PIN_MAPPING_INCLUDED_
-# error "You have defined ADAFRUIT_RGBMATRIX_HAT_PWM which is for the Adafruit HAT. So you also need to set HARDWARE_DESC=adafruit-hat"
-#endif
-
-#ifndef RGB_PARALLEL_CHAINS
-# error "Your pin-mapping.h file should contain an RGB_PARALLEL_CHAINS macro"
-#endif
-
// We need one global instance of a timing correct pulser. There are different
// implementations depending on the context.
static PinPulser *sOutputEnablePulser = NULL;
@@ -74,6 +59,8 @@ PixelMapper::~PixelMapper() {
delete [] buffer_;
}
+const struct HardwareMapping *Framebuffer::hardware_mapping_ = NULL;
+
Framebuffer::Framebuffer(int rows, int columns, int parallel,
int scan_mode,
bool swap_green_blue, bool inverse_color,
@@ -87,16 +74,19 @@ Framebuffer::Framebuffer(int rows, int columns, int parallel,
pwm_bits_(kBitPlanes), do_luminance_correct_(true), brightness_(100),
double_rows_(rows / SUB_PANELS_), row_mask_(double_rows_ - 1),
shared_mapper_(mapper) {
+ assert(hardware_mapping_ != NULL); // Called InitHardwareMapping() ?
assert(shared_mapper_ != NULL); // Storage should be provided by RGBMatrix.
assert(rows_ == 8 || rows_ == 16 || rows_ == 32 || rows_ == 64);
- assert(parallel >= 1 && parallel <= 3);
- if (parallel > RGB_PARALLEL_CHAINS) {
- fprintf(stderr, "Parallel of %d is higher than the supported "
- "RGB_PARALLEL_CHAINS of %d\n", parallel, RGB_PARALLEL_CHAINS);
- assert(parallel == 1);
+ if (parallel > hardware_mapping_->max_parallel_chains) {
+ fprintf(stderr, "The %s GPIO mapping only supports %d parallel chain%s, "
+ "but %d was requested.\n", hardware_mapping_->name,
+ hardware_mapping_->max_parallel_chains,
+ hardware_mapping_->max_parallel_chains > 1 ? "s" : "", parallel);
+ abort();
}
+ assert(parallel >= 1 && parallel <= 3);
- bitplane_buffer_ = new IoBits [double_rows_ * columns_ * kBitPlanes];
+ bitplane_buffer_ = new gpio_bits_t[double_rows_ * columns_ * kBitPlanes];
// If we're the first Framebuffer created, the shared PixelMapper is
// still NULL, so create one.
@@ -122,67 +112,81 @@ Framebuffer::~Framebuffer() {
delete [] bitplane_buffer_;
}
+// TODO: this should also be parsed from some special formatted string, e.g.
+// {addr={22,23,24,25,15},oe=18,clk=17,strobe=4, p0={11,27,7,8,9,10},...}
+/* static */ void Framebuffer::InitHardwareMapping(const char *named_hardware) {
+ if (named_hardware == NULL || *named_hardware == '\0') {
+ named_hardware = "regular";
+ }
+
+ struct HardwareMapping *mapping = NULL;
+ for (HardwareMapping *it = matrix_hardware_mappings; it->name; ++it) {
+ if (strcasecmp(it->name, named_hardware) == 0) {
+ mapping = it;
+ break;
+ }
+ }
+
+ if (!mapping) {
+ fprintf(stderr, "There is no hardware mapping named '%s'.\nAvailable: ",
+ named_hardware);
+ for (HardwareMapping *it = matrix_hardware_mappings; it->name; ++it) {
+ if (it != matrix_hardware_mappings) fprintf(stderr, ", ");
+ fprintf(stderr, "'%s'", it->name);
+ }
+ fprintf(stderr, "\n");
+ abort();
+ }
+
+ if (mapping->max_parallel_chains == 0) {
+ // Auto determine.
+ struct HardwareMapping *h = mapping;
+ if ((h->p0_r1 | h->p0_g1 | h->p0_g1 | h->p0_r2 | h->p0_g2 | h->p0_g2) > 0)
+ ++mapping->max_parallel_chains;
+ if ((h->p1_r1 | h->p1_g1 | h->p1_g1 | h->p1_r2 | h->p1_g2 | h->p1_g2) > 0)
+ ++mapping->max_parallel_chains;
+ if ((h->p2_r1 | h->p2_g1 | h->p2_g1 | h->p2_r2 | h->p2_g2 | h->p2_g2) > 0)
+ ++mapping->max_parallel_chains;
+ }
+ hardware_mapping_ = mapping;
+}
+
/* static */ void Framebuffer::InitGPIO(GPIO *io, int rows, int parallel,
bool allow_hardware_pulsing,
int pwm_lsb_nanoseconds) {
if (sOutputEnablePulser != NULL)
return; // already initialized.
+ const struct HardwareMapping &h = *hardware_mapping_;
// Tell GPIO about all bits we intend to use.
- IoBits b;
- b.raw = 0;
+ gpio_bits_t all_used_bits = 0;
-#ifdef PI_REV1_RGB_PINOUT
- // This is only to be enabled with classic pinout.
- b.bits.output_enable_rev1 = b.bits.output_enable_rev2 = 1;
- b.bits.clock_rev1 = b.bits.clock_rev2 = 1;
-#endif
+ all_used_bits |= h.output_enable | h.clock | h.strobe;
- b.bits.output_enable = 1;
- b.bits.clock = 1;
- b.bits.strobe = 1;
-
- b.bits.p0_r1 = b.bits.p0_g1 = b.bits.p0_b1 = 1;
- b.bits.p0_r2 = b.bits.p0_g2 = b.bits.p0_b2 = 1;
-
-#if RGB_PARALLEL_CHAINS >= 2
+ all_used_bits |= h.p0_r1 | h.p0_g1 | h.p0_b1 | h.p0_r2 | h.p0_g2 | h.p0_b2;
if (parallel >= 2) {
- b.bits.p1_r1 = b.bits.p1_g1 = b.bits.p1_b1 = 1;
- b.bits.p1_r2 = b.bits.p1_g2 = b.bits.p1_b2 = 1;
+ all_used_bits |= h.p1_r1 | h.p1_g1 | h.p1_b1 | h.p1_r2 | h.p1_g2 | h.p1_b2;
}
-#endif
-
-#if RGB_PARALLEL_CHAINS >= 3
if (parallel >= 3) {
- b.bits.p2_r1 = b.bits.p2_g1 = b.bits.p2_b1 = 1;
- b.bits.p2_r2 = b.bits.p2_g2 = b.bits.p2_b2 = 1;
+ all_used_bits |= h.p2_r1 | h.p2_g1 | h.p2_b1 | h.p2_r2 | h.p2_g2 | h.p2_b2;
}
-#endif
const int double_rows = rows / 2;
- if (double_rows >= 32) b.bits.e = 1;
- if (double_rows >= 16) b.bits.d = 1;
- if (double_rows >= 8) b.bits.c = 1;
- if (double_rows >= 4) b.bits.b = 1;
- b.bits.a = 1;
+ if (double_rows >= 32) all_used_bits |= h.e;
+ if (double_rows >= 16) all_used_bits |= h.d;
+ if (double_rows >= 8) all_used_bits |= h.c;
+ if (double_rows >= 4) all_used_bits |= h.b;
+ all_used_bits |= h.a;
// Initialize outputs, make sure that all of these are supported bits.
- const uint32_t result = io->InitOutputs(b.raw);
- assert(result == b.raw);
-
- // Now, set up the PinPulser for output enable.
- IoBits output_enable_bits;
-#ifdef PI_REV1_RGB_PINOUT
- output_enable_bits.bits.output_enable_rev1
- = output_enable_bits.bits.output_enable_rev2 = 1;
-#endif
- output_enable_bits.bits.output_enable = 1;
+ const uint32_t result = io->InitOutputs(all_used_bits);
+ assert(result == all_used_bits); // Impl: all bits declared in gpio.cc ?
std::vector bitplane_timings;
for (int b = 0; b < kBitPlanes; ++b) {
bitplane_timings.push_back(pwm_lsb_nanoseconds << b);
}
- sOutputEnablePulser = PinPulser::Create(io, output_enable_bits.raw,
+ sOutputEnablePulser = PinPulser::Create(io, h.output_enable,
allow_hardware_pulsing,
bitplane_timings);
}
@@ -194,8 +198,7 @@ bool Framebuffer::SetPWMBits(uint8_t value) {
return true;
}
-inline Framebuffer::IoBits *Framebuffer::ValueAt(int double_row,
- int column, int bit) {
+inline gpio_bits_t *Framebuffer::ValueAt(int double_row, int column, int bit) {
return &bitplane_buffer_[ double_row * (columns_ * kBitPlanes)
+ bit * columns_
+ column ];
@@ -272,27 +275,22 @@ void Framebuffer::Fill(uint8_t r, uint8_t g, uint8_t b) {
} else {
MapColors(r, g, b, &red, &blue, &green);
}
+ const struct HardwareMapping &h = *hardware_mapping_;
+ gpio_bits_t all_r = h.p0_r1 | h.p0_r2 | h.p1_r1 | h.p1_r2 | h.p2_r1 | h.p2_r2;
+ gpio_bits_t all_g = h.p0_g1 | h.p0_g2 | h.p1_g1 | h.p1_g2 | h.p2_g1 | h.p2_g2;
+ gpio_bits_t all_b = h.p0_b1 | h.p0_b2 | h.p1_b1 | h.p1_b2 | h.p2_b1 | h.p2_b2;
for (int b = kBitPlanes - pwm_bits_; b < kBitPlanes; ++b) {
uint16_t mask = 1 << b;
- IoBits plane_bits;
- plane_bits.raw = 0;
- plane_bits.bits.p0_r1 = plane_bits.bits.p0_r2 = (red & mask) == mask;
- plane_bits.bits.p0_g1 = plane_bits.bits.p0_g2 = (green & mask) == mask;
- plane_bits.bits.p0_b1 = plane_bits.bits.p0_b2 = (blue & mask) == mask;
+ gpio_bits_t plane_bits = 0;
+ plane_bits |= ((red & mask) == mask) ? all_r : 0;
+ plane_bits |= ((green & mask) == mask) ? all_g : 0;
+ plane_bits |= ((blue & mask) == mask) ? all_b : 0;
-#if RGB_PARALLEL_CHAINS > 1
- plane_bits.bits.p1_r1 = plane_bits.bits.p1_r2 =
- plane_bits.bits.p2_r1 = plane_bits.bits.p2_r2 = (red & mask) == mask;
- plane_bits.bits.p1_g1 = plane_bits.bits.p1_g2 =
- plane_bits.bits.p2_g1 = plane_bits.bits.p2_g2 = (green & mask) == mask;
- plane_bits.bits.p1_b1 = plane_bits.bits.p1_b2 =
- plane_bits.bits.p2_b1 = plane_bits.bits.p2_b2 = (blue & mask) == mask;
-#endif
for (int row = 0; row < double_rows_; ++row) {
- IoBits *row_data = ValueAt(row, 0, b);
+ uint32_t *row_data = ValueAt(row, 0, b);
for (int col = 0; col < columns_; ++col) {
- (row_data++)->raw = plane_bits.raw;
+ *row_data++ = plane_bits;
}
}
}
@@ -314,7 +312,7 @@ void Framebuffer::SetPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
MapColors(r, g, b, &red, &blue, &green);
}
- IoBits *bits = bitplane_buffer_ + pos;
+ uint32_t *bits = bitplane_buffer_ + pos;
const int min_bit_plane = kBitPlanes - pwm_bits_;
bits += (columns_ * min_bit_plane);
const uint32_t r_bits = designator->r_bit;
@@ -327,101 +325,69 @@ void Framebuffer::SetPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
if (red & mask) color_bits |= r_bits;
if (green & mask) color_bits |= g_bits;
if (blue & mask) color_bits |= b_bits;
- bits->raw = (bits->raw & designator_mask) | color_bits;
+ *bits = (*bits & designator_mask) | color_bits;
bits += columns_;
}
}
void Framebuffer::InitDefaultDesignator(int x, int y, PixelDesignator *d) {
- IoBits *bits = ValueAt(y & row_mask_, x, 0);
+ const struct HardwareMapping &h = *hardware_mapping_;
+ uint32_t *bits = ValueAt(y & row_mask_, x, 0);
d->gpio_word = bits - bitplane_buffer_;
d->r_bit = d->g_bit = d->b_bit = 0;
if (y < rows_) {
if (y < double_rows_) {
- color_bits(&d->r_bit).bits.p0_r1 = 1;
- color_bits(&d->g_bit).bits.p0_g1 = 1;
- color_bits(&d->b_bit).bits.p0_b1 = 1;
+ d->r_bit = h.p0_r1;
+ d->g_bit = h.p0_g1;
+ d->b_bit = h.p0_b1;
} else {
- color_bits(&d->r_bit).bits.p0_r2 = 1;
- color_bits(&d->g_bit).bits.p0_g2 = 1;
- color_bits(&d->b_bit).bits.p0_b2 = 1;
+ d->r_bit = h.p0_r2;
+ d->g_bit = h.p0_g2;
+ d->b_bit = h.p0_b2;
}
}
-#if RGB_PARALLEL_CHAINS >= 2
else if (y >= rows_ && y < 2 * rows_) {
if (y - rows_ < double_rows_) {
- color_bits(&d->r_bit).bits.p1_r1 = 1;
- color_bits(&d->g_bit).bits.p1_g1 = 1;
- color_bits(&d->b_bit).bits.p1_b1 = 1;
+ d->r_bit = h.p1_r1;
+ d->g_bit = h.p1_g1;
+ d->b_bit = h.p1_b1;
} else {
- color_bits(&d->r_bit).bits.p1_r2 = 1;
- color_bits(&d->g_bit).bits.p1_g2 = 1;
- color_bits(&d->b_bit).bits.p1_b2 = 1;
+ d->r_bit = h.p1_r2;
+ d->g_bit = h.p1_g2;
+ d->b_bit = h.p1_b2;
}
}
-#endif
-#if RGB_PARALLEL_CHAINS >= 3
else {
if (y - 2*rows_ < double_rows_) {
- color_bits(&d->r_bit).bits.p2_r1 = 1;
- color_bits(&d->g_bit).bits.p2_g1 = 1;
- color_bits(&d->b_bit).bits.p2_b1 = 1;
+ d->r_bit = h.p2_r1;
+ d->g_bit = h.p2_g1;
+ d->b_bit = h.p2_b1;
} else {
- color_bits(&d->r_bit).bits.p2_r2 = 1;
- color_bits(&d->g_bit).bits.p2_g2 = 1;
- color_bits(&d->b_bit).bits.p2_b2 = 1;
+ d->r_bit = h.p2_r2;
+ d->g_bit = h.p2_g2;
+ d->b_bit = h.p2_b2;
}
}
-#endif
+
d->mask = ~(d->r_bit | d->g_bit | d->b_bit);
}
void Framebuffer::DumpToMatrix(GPIO *io) {
- IoBits color_clk_mask; // Mask of bits we need to set while clocking in.
- color_clk_mask.bits.p0_r1
- = color_clk_mask.bits.p0_g1
- = color_clk_mask.bits.p0_b1
- = color_clk_mask.bits.p0_r2
- = color_clk_mask.bits.p0_g2
- = color_clk_mask.bits.p0_b2 = 1;
-
-#if RGB_PARALLEL_CHAINS >= 2
+ const struct HardwareMapping &h = *hardware_mapping_;
+ gpio_bits_t color_clk_mask = 0; // Mask of bits while clocking in.
+ color_clk_mask |= h.p0_r1 | h.p0_g1 | h.p0_b1 | h.p0_r2 | h.p0_g2 | h.p0_b2;
if (parallel_ >= 2) {
- color_clk_mask.bits.p1_r1
- = color_clk_mask.bits.p1_g1
- = color_clk_mask.bits.p1_b1
- = color_clk_mask.bits.p1_r2
- = color_clk_mask.bits.p1_g2
- = color_clk_mask.bits.p1_b2 = 1;
+ color_clk_mask |= h.p1_r1 | h.p1_g1 | h.p1_b1 | h.p1_r2 | h.p1_g2 | h.p1_b2;
}
-#endif
-
-#if RGB_PARALLEL_CHAINS >= 3
if (parallel_ >= 3) {
- color_clk_mask.bits.p2_r1
- = color_clk_mask.bits.p2_g1
- = color_clk_mask.bits.p2_b1
- = color_clk_mask.bits.p2_r2
- = color_clk_mask.bits.p2_g2
- = color_clk_mask.bits.p2_b2 = 1;
+ color_clk_mask |= h.p2_r1 | h.p2_g1 | h.p2_b1 | h.p2_r2 | h.p2_g2 | h.p2_b2;
}
-#endif
-#ifdef PI_REV1_RGB_PINOUT
- color_clk_mask.bits.clock_rev1 = color_clk_mask.bits.clock_rev2 = 1;
-#endif
- color_clk_mask.bits.clock = 1;
+ color_clk_mask |= h.clock;
- IoBits row_mask;
- row_mask.bits.a = row_mask.bits.b = row_mask.bits.c
- = row_mask.bits.d = row_mask.bits.e = 1;
+ const gpio_bits_t row_mask = h.a | h.b | h.c | h.d | h.e;
- IoBits clock, strobe, row_address;
-#ifdef PI_REV1_RGB_PINOUT
- clock.bits.clock_rev1 = clock.bits.clock_rev2 = 1;
-#endif
- clock.bits.clock = 1;
- strobe.bits.strobe = 1;
+ gpio_bits_t row_address;
// info needed for interlace mode.
uint8_t rot_bits = 0;
@@ -445,32 +411,32 @@ void Framebuffer::DumpToMatrix(GPIO *io) {
d_row = ((row_loop << 1) | (row_loop >> rot_bits)) & row_mask_;
}
- row_address.bits.a = d_row;
- row_address.bits.b = d_row >> 1;
- row_address.bits.c = d_row >> 2;
- row_address.bits.d = d_row >> 3;
- row_address.bits.e = d_row >> 4;
+ row_address = (d_row & 0x01) ? h.a : 0;
+ row_address |= (d_row & 0x02) ? h.b : 0;
+ row_address |= (d_row & 0x04) ? h.c : 0;
+ row_address |= (d_row & 0x08) ? h.d : 0;
+ row_address |= (d_row & 0x10) ? h.e : 0;
// 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) {
- IoBits *row_data = ValueAt(d_row, 0, b);
+ gpio_bits_t *row_data = ValueAt(d_row, 0, b);
// While the output enable is still on, we can already clock in the next
// data.
for (int col = 0; col < columns_; ++col) {
- const IoBits &out = *row_data++;
- io->WriteMaskedBits(out.raw, color_clk_mask.raw); // col + reset clock
- io->SetBits(clock.raw); // Rising edge: clock color in.
+ const gpio_bits_t &out = *row_data++;
+ io->WriteMaskedBits(out, color_clk_mask); // col + reset clock
+ io->SetBits(h.clock); // Rising edge: clock color in.
}
- io->ClearBits(color_clk_mask.raw); // clock back to normal.
+ io->ClearBits(color_clk_mask); // clock back to normal.
// 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);
+ io->WriteMaskedBits(row_address, row_mask); // Set row address
+ io->SetBits(h.strobe); // Strobe in the previously clocked in row.
+ io->ClearBits(h.strobe);
// Now switch on for the sleep time necessary for that bit-plane.
sOutputEnablePulser->SendPulse(b);
diff --git a/lib/hardware-mapping.c b/lib/hardware-mapping.c
new file mode 100644
index 0000000..abc5038
--- /dev/null
+++ b/lib/hardware-mapping.c
@@ -0,0 +1,185 @@
+/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+ * Copyright (C) 2013, 2016 Henner Zeller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+
+/*
+ * We do this in plain C so that we can use designated initializers.
+ */
+#include "hardware-mapping.h"
+
+#define GPIO_BIT(b) (1<<(b))
+
+struct HardwareMapping matrix_hardware_mappings[] = {
+ /*
+ * The regular hardware mapping described in the wiring.md and used
+ * by the adapter PCBs.
+ */
+ {
+ .name = "regular",
+
+ .output_enable = GPIO_BIT(18),
+ .clock = GPIO_BIT(17),
+ .strobe = GPIO_BIT(4),
+
+ /* Address lines */
+ .a = GPIO_BIT(22),
+ .b = GPIO_BIT(23),
+ .c = GPIO_BIT(24),
+ .d = GPIO_BIT(25),
+ .e = GPIO_BIT(15), /* RxD kept free unless 1:64 */
+
+ /* Parallel chain 0, RGB for both sub-panels */
+ .p0_r1 = GPIO_BIT(11), /* masks: SPI0_SCKL */
+ .p0_g1 = GPIO_BIT(27), /* Not on RPi1, Rev1 */
+ .p0_b1 = GPIO_BIT(7), /* masks: SPI0_CE1 */
+ .p0_r2 = GPIO_BIT(8), /* masks: SPI0_CE0 */
+ .p0_g2 = GPIO_BIT(9), /* masks: SPI0_MISO */
+ .p0_b2 = GPIO_BIT(10), /* masks: SPI0_MOSI */
+
+ /* All the following are only available with 40 GPIP pins, on A+/B+/Pi2,3 */
+ /* Chain 1 */
+ .p1_r1 = GPIO_BIT(12),
+ .p1_g1 = GPIO_BIT(5),
+ .p1_b1 = GPIO_BIT(6),
+ .p1_r2 = GPIO_BIT(19),
+ .p1_g2 = GPIO_BIT(13),
+ .p1_b2 = GPIO_BIT(20),
+
+ /* Chain 2 */
+ .p2_r1 = GPIO_BIT(14), /* masks TxD when parallel=3 */
+ .p2_g1 = GPIO_BIT(2), /* masks SCL when parallel=3 */
+ .p2_b1 = GPIO_BIT(3), /* masks SDA when parallel=3 */
+ .p2_r2 = GPIO_BIT(26),
+ .p2_g2 = GPIO_BIT(16),
+ .p2_b2 = GPIO_BIT(21),
+ },
+
+ /*
+ * This is used if you have an Adafruit HAT in the default configuration
+ */
+ {
+ .name = "adafruit-hat",
+
+ .output_enable = GPIO_BIT(4),
+ .clock = GPIO_BIT(17),
+ .strobe = GPIO_BIT(21),
+
+ .a = GPIO_BIT(22),
+ .b = GPIO_BIT(26),
+ .c = GPIO_BIT(27),
+ .d = GPIO_BIT(20),
+ .e = GPIO_BIT(24), /* Needs manual wiring, see README.md */
+
+ .p0_r1 = GPIO_BIT(5),
+ .p0_g1 = GPIO_BIT(13),
+ .p0_b1 = GPIO_BIT(6),
+ .p0_r2 = GPIO_BIT(12),
+ .p0_g2 = GPIO_BIT(16),
+ .p0_b2 = GPIO_BIT(23),
+ },
+
+ /*
+ * An Adafruit HAT with the PWM modification
+ */
+ {
+ .name = "adafruit-hat-pwm",
+
+ .output_enable = GPIO_BIT(18), /* The only change compared to above */
+ .clock = GPIO_BIT(17),
+ .strobe = GPIO_BIT(21),
+
+ .a = GPIO_BIT(22),
+ .b = GPIO_BIT(26),
+ .c = GPIO_BIT(27),
+ .d = GPIO_BIT(20),
+ .e = GPIO_BIT(24),
+
+ .p0_r1 = GPIO_BIT(5),
+ .p0_g1 = GPIO_BIT(13),
+ .p0_b1 = GPIO_BIT(6),
+ .p0_r2 = GPIO_BIT(12),
+ .p0_g2 = GPIO_BIT(16),
+ .p0_b2 = GPIO_BIT(23),
+ },
+
+ /*
+ * Classic: Early forms of this library had this as default mapping, mostly
+ * derived from the 26 GPIO-header version so that it also can work
+ * on 40 Pin GPIO headers with more parallel chains.
+ * Not used anymore.
+ */
+ {
+ .name = "classic",
+
+ .output_enable = GPIO_BIT(27), /* Not available on RPi1, Rev 1 */
+ .clock = GPIO_BIT(11),
+ .strobe = GPIO_BIT(4),
+
+ .a = GPIO_BIT(7),
+ .b = GPIO_BIT(8),
+ .c = GPIO_BIT(9),
+ .d = GPIO_BIT(10),
+
+ .p0_r1 = GPIO_BIT(17),
+ .p0_g1 = GPIO_BIT(18),
+ .p0_b1 = GPIO_BIT(22),
+ .p0_r2 = GPIO_BIT(23),
+ .p0_g2 = GPIO_BIT(24),
+ .p0_b2 = GPIO_BIT(25),
+
+ .p1_r1 = GPIO_BIT(12),
+ .p1_g1 = GPIO_BIT(5),
+ .p1_b1 = GPIO_BIT(6),
+ .p1_r2 = GPIO_BIT(19),
+ .p1_g2 = GPIO_BIT(13),
+ .p1_b2 = GPIO_BIT(20),
+
+ .p2_r1 = GPIO_BIT(14), /* masks TxD if parallel = 3 */
+ .p2_g1 = GPIO_BIT(2), /* masks SDA if parallel = 3 */
+ .p2_b1 = GPIO_BIT(3), /* masks SCL if parallel = 3 */
+ .p2_r2 = GPIO_BIT(15),
+ .p2_g2 = GPIO_BIT(26),
+ .p2_b2 = GPIO_BIT(21),
+ },
+
+ /*
+ * Classic pin-out for Rev-A Raspberry Pi.
+ */
+ {
+ .name = "classic-pi1",
+
+ /* The Revision-1 and Revision-2 boards have different GPIO mappings
+ * on the P1-3 and P1-5. So we use both interpretations.
+ * To keep the I2C pins free, we avoid these in later mappings.
+ */
+ .output_enable = GPIO_BIT(0) | GPIO_BIT(2),
+ .clock = GPIO_BIT(1) | GPIO_BIT(3),
+ .strobe = GPIO_BIT(4),
+
+ .a = GPIO_BIT(7),
+ .b = GPIO_BIT(8),
+ .c = GPIO_BIT(9),
+ .d = GPIO_BIT(10),
+
+ .p0_r1 = GPIO_BIT(17),
+ .p0_g1 = GPIO_BIT(18),
+ .p0_b1 = GPIO_BIT(22),
+ .p0_r2 = GPIO_BIT(23),
+ .p0_g2 = GPIO_BIT(24),
+ .p0_b2 = GPIO_BIT(25),
+ },
+
+ {0}
+};
diff --git a/lib/hardware-mapping.h b/lib/hardware-mapping.h
new file mode 100644
index 0000000..accce26
--- /dev/null
+++ b/lib/hardware-mapping.h
@@ -0,0 +1,53 @@
+/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+ * Copyright (C) 2013 Henner Zeller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+#ifndef RPI_HARDWARE_MAPPING_H
+#define RPI_HARDWARE_MAPPING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+typedef uint32_t gpio_bits_t; /* this should probably come from gpio.h */
+
+struct HardwareMapping {
+ const char *name;
+ int max_parallel_chains;
+
+ gpio_bits_t output_enable;
+ gpio_bits_t clock;
+ gpio_bits_t strobe;
+
+ gpio_bits_t a, b, c, d, e;
+
+ gpio_bits_t p0_r1, p0_g1, p0_b1;
+ gpio_bits_t p0_r2, p0_g2, p0_b2;
+
+ gpio_bits_t p1_r1, p1_g1, p1_b1;
+ gpio_bits_t p1_r2, p1_g2, p1_b2;
+
+ gpio_bits_t p2_r1, p2_g1, p2_b1;
+ gpio_bits_t p2_r2, p2_g2, p2_b2;
+};
+
+extern struct HardwareMapping matrix_hardware_mappings[];
+
+#ifdef __cplusplus
+} // extern C
+#endif
+
+#endif
diff --git a/lib/hardware/README b/lib/hardware/README
deleted file mode 100644
index 7c3897c..0000000
--- a/lib/hardware/README
+++ /dev/null
@@ -1,3 +0,0 @@
-These sub-directories contain include files that are specific for the
-particular hardware used.
-They are chosen at compile-time with the HARDWARE_DESC variable in lib/Makefile.
diff --git a/lib/hardware/adafruit-hat/led-panel-pin-mapping.h b/lib/hardware/adafruit-hat/led-panel-pin-mapping.h
deleted file mode 100644
index 77fbcb7..0000000
--- a/lib/hardware/adafruit-hat/led-panel-pin-mapping.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
-// Adafruit made a HAT to work with this library, but it has a slightly
-// different GPIO mapping. This is this mapping. A variant of this mapping
-// allows using the Raspberry Pi PWM hardware. This requires modifying the
-// HAT to connect GPIO 4 and 18. See #else for regular mapping.
-
-#define RGB_PARALLEL_CHAINS 1
-#define FYI_ADAFRUIT_HAT_PIN_MAPPING_INCLUDED_ 1
-
-union IoBits {
- struct {
- // This bitset reflects the GPIO mapping. The naming of the
- // pins of type 'p0_r1' means 'first parallel chain, red-bit one'
- unsigned int unused_0_3 : 4; // 0..3
-#ifdef ADAFRUIT_RGBMATRIX_HAT_PWM
- unsigned int unused_4 : 1; // 4
-#else
- unsigned int output_enable : 1; // 4
-#endif
- unsigned int p0_r1 : 1; // 5
- unsigned int p0_b1 : 1; // 6
- unsigned int unused_7_11 : 5; // 7..11
- unsigned int p0_r2 : 1; // 12
- unsigned int p0_g1 : 1; // 13
- unsigned int unused_14_15 : 2; // 14,15
- unsigned int p0_g2 : 1; // 16
- unsigned int clock : 1; // 17
-#ifdef ADAFRUIT_RGBMATRIX_HAT_PWM
- unsigned int output_enable : 1; // 18
- unsigned int unused_19 : 1; // 19
-#else
- unsigned int unused_18_19 : 2; // 18,19
-#endif
- unsigned int d : 1; // 20
- unsigned int strobe : 1; // 21
- unsigned int a : 1; // 22
- unsigned int p0_b2 : 1; // 23
- unsigned int e : 1; // 24 // Needs manual wiring
- unsigned int unused_25 : 1; // 25
- unsigned int b : 1; // 26
- unsigned int c : 1; // 27
- } bits;
- uint32_t raw;
- IoBits() : raw(0) {}
-};
diff --git a/lib/hardware/classic/led-panel-pin-mapping.h b/lib/hardware/classic/led-panel-pin-mapping.h
deleted file mode 100644
index 382c5d9..0000000
--- a/lib/hardware/classic/led-panel-pin-mapping.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
-// Classic pinout before July 2015. Consider upgrading to the new pinout.
-#define RGB_PARALLEL_CHAINS 3
-union IoBits {
- struct {
- // This bitset reflects the GPIO mapping. The naming of the
- // pins of type 'p0_r1' means 'first parallel chain, red-bit one'
-#ifdef PI_REV1_RGB_PINOUT
- // TODO(hzeller): Maybe break out this rev1 mapping. I don't have a
- // Rev1 Pi to test though, so this is it for now.
-# undef RGB_PARALLEL_CHAINS
-# define RGB_PARALLEL_CHAINS 1
- // The Revision1 and Revision2 boards have different GPIO mappings
- // on the pins 2 and 3. Just use both interpretations.
- // To keep the I2C pins free, we don't use these anymore.
- unsigned int output_enable_rev1 : 1; // 0 (RPi 1, Revision 1)
- unsigned int clock_rev1 : 1; // 1 (RPi 1, Revision 1)
- unsigned int output_enable_rev2 : 1; // 2 (Pi1.Rev2; masks: I2C SDA)
- unsigned int clock_rev2 : 1; // 3 (Pi1.Rev2; masks: I2C SCL)
-#else
- unsigned int unused_0_1 : 2; // 0..1 (only on RPi 1, Revision 1)
- unsigned int p2_g1 : 1; // 2 (masks SDA when parallel=3)
- unsigned int p2_b1 : 1; // 3 (masks SCL when parallel=3)
-#endif
- unsigned int strobe : 1; // 4
- unsigned int p1_g1 : 1; // 5 (only on A+/B+/Pi2)
- unsigned int p1_b1 : 1; // 6 (only on A+/B+/Pi2)
- // row: 7..10, but separated as seprate bits to make it easier to shuffle
- // bits if needed.
- unsigned int a : 1; // 7 (masks: SPI0_CE1)
- unsigned int b : 1; // 8 (masks: SPI0_CE0)
- unsigned int c : 1; // 9 (masks: SPI0_MISO)
- unsigned int d : 1; // 10 (masks: SPI0_MOSI)
- unsigned int clock : 1; // 11 (masks: SPI0_SCKL)
- unsigned int p1_r1 : 1; // 12 (only on A+/B+/Pi2)
- unsigned int p1_g2 : 1; // 13 (only on A+/B+/Pi2)
- unsigned int p2_r1 : 1; // 14 (masks TxD when parallel=3)
- unsigned int p2_r2 : 1; // 15 (masks RxD when parallel=3)
- unsigned int e : 1; // 16 (only on A+/B+/Pi2)
- unsigned int p0_r1 : 1; // 17
- unsigned int p0_g1 : 1; // 18
- unsigned int p1_r2 : 1; // 19 (only on A+/B+/Pi2)
- unsigned int p1_b2 : 1; // 20 (only on A+/B+/Pi2)
- unsigned int p2_b2 : 1; // 21 (only on A+/B+/Pi2)
- unsigned int p0_b1 : 1; // 22
- unsigned int p0_r2 : 1; // 23
- unsigned int p0_g2 : 1; // 24
- unsigned int p0_b2 : 1; // 25
- unsigned int p2_g2 : 1; // 26 (only on A+/B+/Pi2)
- unsigned int output_enable : 1; // 27 (Not on RPi1, Rev1)
- } bits;
- uint32_t raw;
- IoBits() : raw(0) {}
-};
diff --git a/lib/hardware/regular/led-panel-pin-mapping.h b/lib/hardware/regular/led-panel-pin-mapping.h
deleted file mode 100644
index 0f4b866..0000000
--- a/lib/hardware/regular/led-panel-pin-mapping.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
-// Standard pinout since July 2015
-// This uses the PWM pin to create the timing.
-#define RGB_PARALLEL_CHAINS 3
-union IoBits {
- struct {
- // This bitset reflects the GPIO mapping. The naming of the
- // pins of type 'p0_r1' means 'first parallel chain, red-bit one'
- // GPIO Header-pos
- unsigned int unused_0_1 : 2; // 0..1 (only on RPi 1, Revision 1)
- unsigned int p2_g1 : 1; // 2 P1-03 (masks SDA when parallel=3)
- unsigned int p2_b1 : 1; // 3 P1-05 (masks SCL when parallel=3)
- unsigned int strobe : 1; // 4 P1-07
- unsigned int p1_g1 : 1; // 5 P1-29 (only on A+/B+/Pi2)
- unsigned int p1_b1 : 1; // 6 P1-31 (only on A+/B+/Pi2)
- // TODO: be able to disable chain 0 for higher-pin RPis to gain SPI back.
- unsigned int p0_b1 : 1; // 7 P1-26 (masks: SPI0_CE1)
- unsigned int p0_r2 : 1; // 8 P1-24 (masks: SPI0_CE0)
- unsigned int p0_g2 : 1; // 9 P1-21 (masks: SPI0_MISO
- unsigned int p0_b2 : 1; // 10 P1-19 (masks: SPI0_MOSI)
- unsigned int p0_r1 : 1; // 11 P1-23 (masks: SPI0_SCKL)
-
- unsigned int p1_r1 : 1; // 12 P1-32 (only on A+/B+/Pi2)
- unsigned int p1_g2 : 1; // 13 P1-33 (only on A+/B+/Pi2)
- unsigned int p2_r1 : 1; // 14 P1-08 (masks TxD when parallel=3)
- unsigned int e : 1; // 15 P1-10 (RxD) - kept free unless 1:64
- unsigned int p2_g2 : 1; // 16 P1-36 (only on A+/B+/Pi2)
-
- unsigned int clock : 1; // 17 P1-11
-
- unsigned int output_enable : 1; // 18 P1-12 (PWM pin: our timing)
- unsigned int p1_r2 : 1; // 19 P1-35 (only on A+/B+/Pi2)
- unsigned int p1_b2 : 1; // 20 P1-38 (only on A+/B+/Pi2)
- unsigned int p2_b2 : 1; // 21 P1-40 (only on A+/B+/Pi2)
-
- unsigned int a : 1; // 22 P1-15 // row bits.
- unsigned int b : 1; // 23 P1-16
- unsigned int c : 1; // 24 P1-18
- unsigned int d : 1; // 25 P1-22
-
- unsigned int p2_r2 : 1; // 26 P1-37 (only on A+/B+/Pi2)
- unsigned int p0_g1 : 1; // 27 P1-13 (Not on RPi1, Rev1)
- } bits;
- uint32_t raw;
- IoBits() : raw(0) {}
-};
diff --git a/lib/led-matrix-c.cc b/lib/led-matrix-c.cc
index f20c07f..1f0f246 100644
--- a/lib/led-matrix-c.cc
+++ b/lib/led-matrix-c.cc
@@ -53,6 +53,7 @@ struct RGBLedMatrix *led_matrix_create_from_options(
// C-struct values if available.
// We assume everything non-zero has an explicit value.
#define OPT_COPY_IF_SET(o) if (opts->o) default_opts.o = opts->o
+ OPT_COPY_IF_SET(hardware_mapping);
OPT_COPY_IF_SET(rows);
OPT_COPY_IF_SET(chain_length);
OPT_COPY_IF_SET(parallel);
@@ -77,6 +78,7 @@ struct RGBLedMatrix *led_matrix_create_from_options(
if (opts) {
#define ACTUAL_VALUE_BACK_TO_OPT(o) opts->o = default_opts.o
+ ACTUAL_VALUE_BACK_TO_OPT(hardware_mapping);
ACTUAL_VALUE_BACK_TO_OPT(rows);
ACTUAL_VALUE_BACK_TO_OPT(chain_length);
ACTUAL_VALUE_BACK_TO_OPT(parallel);
diff --git a/lib/led-matrix.cc b/lib/led-matrix.cc
index 86aa3fe..35eeca2 100644
--- a/lib/led-matrix.cc
+++ b/lib/led-matrix.cc
@@ -29,6 +29,22 @@
#include "thread.h"
#include "framebuffer-internal.h"
+// Leave this in here for a while. Setting things from old defines.
+#if defined(ADAFRUIT_RGBMATRIX_HAT)
+# warning "You are using an old way to select the Adafruit HAT by defining -DADAFRUIT_RGBMATRIX_HAT"
+# warning "The new way to do this is to set HARDWARE_DESC=adafruit-hat"
+# warning "Check out https://github.com/hzeller/rpi-rgb-led-matrix#switch-the-pinout"
+# undef DEFAULT_HARDWARE
+# define DEFAULT_HARDWARE "adafruit-hat"
+#endif
+
+#if defined(ADAFRUIT_RGBMATRIX_HAT_PWM)
+# warning "You are using an old way to select the Adafruit HAT with flicker mod by defining -DADAFRUIT_RGBMATRIX_HAT_PWM"
+# warning "The new way to do this is to set HARDWARE_DESC=adafruit-hat-pwm"
+# undef DEFAULT_HARDWARE
+# define DEFAULT_HARDWARE "adafruit-hat-pwm"
+#endif
+
namespace rgb_matrix {
// Pump pixels to screen. Needs to be high priority real-time because jitter
class RGBMatrix::UpdateThread : public Thread {
@@ -110,11 +126,18 @@ private:
};
// Some defaults. See options-initialize.cc for the command line parsing.
-RGBMatrix::Options::Options()
- : rows(32), chain_length(1), parallel(1), pwm_bits(11),
- // Historically, we provided these options only as #defines. Make sure that
- // things still behave as before if someone has set these.
- // At some point: remove them from the Makefile. Later: remove them here.
+RGBMatrix::Options::Options() :
+ // Historically, we provided these options only as #defines. Make sure that
+ // things still behave as before if someone has set these.
+ // At some point: remove them from the Makefile. Later: remove them here.
+#ifdef DEFAULT_HARDWARE
+ hardware_mapping(DEFAULT_HARDWARE),
+#else
+ hardware_mapping("regular"),
+#endif
+
+ rows(32), chain_length(1), parallel(1), pwm_bits(11),
+
#ifdef LSB_PWM_NANOSECONDS
pwm_lsb_nanoseconds(LSB_PWM_NANOSECONDS),
#else
@@ -159,6 +182,7 @@ RGBMatrix::Options::Options()
RGBMatrix::RGBMatrix(GPIO *io, const Options &options)
: params_(options), io_(NULL), updater_(NULL), shared_pixel_mapper_(NULL) {
assert(params_.Validate(NULL));
+ internal::Framebuffer::InitHardwareMapping(params_.hardware_mapping);
active_ = CreateFrameCanvas();
Clear();
SetGPIO(io, true);
@@ -172,6 +196,7 @@ RGBMatrix::RGBMatrix(GPIO *io, int rows, int chained_displays,
params_.chain_length = chained_displays;
params_.parallel = parallel_displays;
assert(params_.Validate(NULL));
+ internal::Framebuffer::InitHardwareMapping(params_.hardware_mapping);
active_ = CreateFrameCanvas();
Clear();
SetGPIO(io, true);
diff --git a/lib/options-initialize.cc b/lib/options-initialize.cc
index bd8fdf6..8aa9969 100644
--- a/lib/options-initialize.cc
+++ b/lib/options-initialize.cc
@@ -95,6 +95,33 @@ static bool ConsumeIntFlag(const char *flag_name,
return true; // consumed.
}
+// The resulting value is allocated.
+static bool ConsumeStringFlag(const char *flag_name,
+ argv_iterator &pos, const argv_iterator end,
+ const char **result_value, int *error) {
+ const char *option = *pos;
+ if (strncmp(option, OPTION_PREFIX, OPTION_PREFIX_LEN) != 0)
+ return false;
+ option += OPTION_PREFIX_LEN;
+ const size_t flag_len = strlen(flag_name);
+ if (strncmp(option, flag_name, flag_len) != 0)
+ return false; // not consumed.
+ const char *value;
+ if (option[flag_len] == '=') // --option=hello # value in same arg
+ value = option + flag_len + 1;
+ else if (pos + 1 < end) { // --option hello # value in next arg
+ value = *(++pos);
+ } else {
+ fprintf(stderr, "Parameter expected after %s%s\n",
+ OPTION_PREFIX, flag_name);
+ ++*error;
+ *result_value = NULL;
+ return true; // consumed, but error.
+ }
+ *result_value = strdup(value); // This will leak, but no big deal.
+ return true;
+}
+
static bool FlagInit(int &argc, char **&argv,
RGBMatrix::Options *mopts,
RuntimeOptions *ropts) {
@@ -110,6 +137,9 @@ static bool FlagInit(int &argc, char **&argv,
for (/**/; it < end; ++it) {
posix_end_option_seen |= (strcmp(*it, "--") == 0);
if (!posix_end_option_seen) {
+ if (ConsumeStringFlag("gpio-mapping", it, end,
+ &mopts->hardware_mapping, &err))
+ continue;
if (ConsumeIntFlag("rows", it, end, &mopts->rows, &err))
continue;
if (ConsumeIntFlag("chain", it, end, &mopts->chain_length, &err))
@@ -282,6 +312,7 @@ RGBMatrix *CreateMatrixFromFlags(int *argc, char ***argv,
void PrintMatrixFlags(FILE *out, const RGBMatrix::Options &d,
const RuntimeOptions &r) {
fprintf(out,
+ "\t--led-gpio-mapping= : Name of GPIO mapping used. Default \"%s\"\n"
"\t--led-rows= : Panel rows. 8, 16, 32 or 64. "
"(Default: %d).\n"
"\t--led-chain= : Number of daisy-chained panels. "
@@ -300,6 +331,7 @@ void PrintMatrixFlags(FILE *out, const RGBMatrix::Options &d,
"\t--led-pwm-lsb-nanoseconds : PWM Nanoseconds for LSB "
"(Default: %d)\n"
"\t--led-%shardware-pulse : %sse hardware pin-pulse generation.\n",
+ d.hardware_mapping,
d.rows, d.chain_length, d.parallel,
d.pwm_bits, d.brightness, d.scan_mode,
d.show_refresh_rate ? "no-" : "", d.show_refresh_rate ? "Don't s" : "S",
diff --git a/utils/README.md b/utils/README.md
index eb02507..ce8e8c1 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -29,6 +29,7 @@ Options:
-R : Rotate output; steps of 90 degrees
General LED matrix options:
+ --led-gpio-mapping= : Name of GPIO mapping used. Default "regular"
--led-rows= : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain= : Number of daisy-chained panels. (Default: 1).
--led-parallel= : For A/B+ models or RPi2,3b: parallel chains. range=1..3 (Default: 1).
diff --git a/utils/led-image-viewer.cc b/utils/led-image-viewer.cc
index 93ad50f..116a629 100644
--- a/utils/led-image-viewer.cc
+++ b/utils/led-image-viewer.cc
@@ -303,6 +303,9 @@ int main(int argc, char *argv[]) {
matrix->ApplyStaticTransformer(rgb_matrix::RotateTransformer(angle));
}
+ printf("Size: %dx%d. Hardware gpio mapping: %s\n",
+ matrix->width(), matrix->height(), matrix_options.hardware_mapping);
+
// These parameters are needed once we do scrolling.
const bool fill_width = false;
const bool fill_height = false;