o Next step in avoiding the need to re-compile: make hardware GPIO

mapping choosable at run-time (and hence: via command line flag).
  Now, Adafruit HAT users don't have to recompile.
This commit is contained in:
Henner Zeller 2016-09-16 19:02:53 -07:00
parent 9cbb4e116e
commit b68d100ae0
21 changed files with 504 additions and 345 deletions

View file

@ -84,8 +84,8 @@ This documentation is split into parts that help you through the process
* <a href="wiring.md"><img src="img/wire-up-icon.png"></a>
[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=<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=<rows> : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain=<chained> : Number of daisy-chained panels. (Default: 1).
--led-parallel=<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):
<a href="img/adafruit-mod.jpg"><img src="img/adafruit-mod.jpg" height="80px"></a>
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,

View file

@ -17,6 +17,7 @@ Options:
in the middle in an U-arrangement to get more vertical space.
-R <rotation> : Sets the rotation of matrix. Allowed: 0, 90, 180, 270. Default: 0.
-t <seconds> : Run for these number of seconds, then exit.
--led-gpio-mapping=<name> : Name of GPIO mapping used. Default "regular"
--led-rows=<rows> : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain=<chained> : Number of daisy-chained panels. (Default: 1).
--led-parallel=<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;

View file

@ -5,6 +5,7 @@
*/
#include "led-matrix-c.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -17,6 +17,8 @@
#include <stdint.h>
#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<IoBits*>(val);
}
gpio_bits_t *bitplane_buffer_;
inline gpio_bits_t *ValueAt(int double_row, int column, int bit);
PixelMapper **shared_mapper_; // Storage in RGBMatrix.
};

View file

@ -19,11 +19,12 @@
#include "framebuffer-internal.h"
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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<int> 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);

185
lib/hardware-mapping.c Normal file
View file

@ -0,0 +1,185 @@
/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
* Copyright (C) 2013, 2016 Henner Zeller <h.zeller@acm.org>
*
* 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 <http: *gnu.org/licenses/gpl-2.0.txt>
*/
/*
* 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}
};

53
lib/hardware-mapping.h Normal file
View file

@ -0,0 +1,53 @@
/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
* Copyright (C) 2013 Henner Zeller <h.zeller@acm.org>
*
* 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 <http: *gnu.org/licenses/gpl-2.0.txt>
*/
#ifndef RPI_HARDWARE_MAPPING_H
#define RPI_HARDWARE_MAPPING_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
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

View file

@ -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.

View file

@ -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) {}
};

View file

@ -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) {}
};

View file

@ -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) {}
};

View file

@ -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);

View file

@ -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);

View file

@ -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> : Name of GPIO mapping used. Default \"%s\"\n"
"\t--led-rows=<rows> : Panel rows. 8, 16, 32 or 64. "
"(Default: %d).\n"
"\t--led-chain=<chained> : 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",

View file

@ -29,6 +29,7 @@ Options:
-R<angle> : Rotate output; steps of 90 degrees
General LED matrix options:
--led-gpio-mapping=<name> : Name of GPIO mapping used. Default "regular"
--led-rows=<rows> : Panel rows. 8, 16, 32 or 64. (Default: 32).
--led-chain=<chained> : Number of daisy-chained panels. (Default: 1).
--led-parallel=<parallel> : For A/B+ models or RPi2,3b: parallel chains. range=1..3 (Default: 1).

View file

@ -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;