Skip to content

Commit

Permalink
Add initialization for FM6126A panels. Use --led-panel-type=FM6126A
Browse files Browse the repository at this point in the history
This is mostly experimental at this point (I only have a single panel
to test, thanks @esden), so please let me know if this works for you.
It is modelled after the Python script that was shared on #746.

Right now, this is not abstracted yet for potential other panel types,
this will be added as we go.

(This works in C++ now. If someone needs this using Python, please update
the Python bindings and send a pull request for the new option).

Fixes #746 #807
  • Loading branch information
hzeller committed Sep 3, 2019
1 parent 9520d3b commit 7160a8a
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 8 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ faster refresh-rate for the same size, but do some multiplexing internally
of which there are a few types out there; they can be chosen with
the `--led-multiplexing` parameter.

There are some panels that have a different chip-set than the default HUB75.
These require some initialization sequence. The current supported one is
`--led-panel-type=FM6126A`.

Generally, the higher scan-rate (e.g. 1:8), a.k.a. outdoor panels generally
allow faster refresh rate, but you might need to figure out the multiplexing
mapping if one of the three provided does not work.
Expand Down Expand Up @@ -185,6 +189,16 @@ This illustrates what each of these parameters mean:

<a href="wiring.md#chaining-parallel-chains-and-coordinate-system"><img src="img/coordinates.png"></a>

##### Panel Type

Typically, panels should just work out of the box, but some panels use a
different chip-set that requires some initialization. If you don't see any
output on your panel, try setting:

```
--led-panel-type=FM6126A
```

##### Multiplexing
If you have some 'outdoor' panels or panels with different multiplexing,
the following will be useful:
Expand Down
6 changes: 6 additions & 0 deletions include/led-matrix-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ struct RGBLedMatrixOptions {
*/
const char *pixel_mapper_config; /* Corresponding flag: --led-pixel-mapper */

/*
* Panel type. Typically just NULL, but certain panels (AM6126) require
* an initialization sequence
*/
const char *panel_type; /* Corresponding flag: --led-panel-type */

/** The following are boolean flags, all off by default **/

/* Allow to use the hardware subsystem to create pulses. This won't do
Expand Down
4 changes: 4 additions & 0 deletions include/led-matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ class RGBMatrix : public Canvas {
// to this matrix. A semicolon-separated list of pixel-mappers with optional
// parameter.
const char *pixel_mapper_config; // Flag: --led-pixel-mapper

// Panel type. Typically an empty string or NULL, but some panels need
// a particular initialization sequence, so this is used for that.
const char *panel_type; // Flag: --led-panel-type
};

// Create an RGBMatrix.
Expand Down
1 change: 1 addition & 0 deletions lib/framebuffer-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class Framebuffer {
int pwm_lsb_nanoseconds,
int dither_bits,
int row_address_type);
static void InitializePanels(GPIO *io, const char *panel_type, int columns);

// Set PWM bits used for output. Default is 11, but if you only deal with
// simple comic-colors, 1 might be sufficient. Lower require less CPU.
Expand Down
51 changes: 51 additions & 0 deletions lib/framebuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,57 @@ Framebuffer::~Framebuffer() {
bitplane_timings);
}

// NOTE: first version for panel initialization sequence, need to refine
// until it is more clear how different panel types are initialized to be
// able to abstract this more.

static void InitFM6126(GPIO *io, const struct HardwareMapping &h, int columns) {
const uint32_t bits_on
= h.p0_r1 | h.p0_g1 | h.p0_b1 | h.p0_r2 | h.p0_g2 | h.p0_b2
| h.p1_r1 | h.p1_g1 | h.p1_b1 | h.p1_r2 | h.p1_g2 | h.p1_b2
| h.p2_r1 | h.p2_g1 | h.p2_b1 | h.p2_r2 | h.p2_g2 | h.p2_b2
| h.a; // Address bit 'A' is always on.
const uint32_t bits_off = h.a;

// Init bits. TODO: customize, as we can do things such as brightness here,
// which would allow more higher quality output.
static const char* init_b12 = "0111111111111111"; // full bright
static const char* init_b13 = "0000000001000000"; // panel on.

io->ClearBits(h.clock | h.strobe);

for (int i = 0; i < columns; ++i) {
uint32_t value = init_b12[i % 16] == '0' ? bits_off : bits_on;
if (i > columns - 12) value |= h.strobe;
io->Write(value);
io->SetBits(h.clock);
io->ClearBits(h.clock);
}
io->ClearBits(h.strobe);

for (int i = 0; i < columns; ++i) {
uint32_t value = init_b13[i % 16] == '0' ? bits_off : bits_on;
if (i > columns - 13) value |= h.strobe;
io->Write(value);
io->SetBits(h.clock);
io->ClearBits(h.clock);
}
io->ClearBits(h.strobe);
}

/*static*/ void Framebuffer::InitializePanels(GPIO *io,
const char *panel_type,
int columns) {
if (!panel_type || panel_type[0] == '\0') return;
if (strncasecmp(panel_type, "fm6126", 6) == 0) {
InitFM6126(io, *hardware_mapping_, columns);
}
// else if (strncasecmp(...)) // more init types
else {
fprintf(stderr, "Unknown panel type '%s'; typo ?\n", panel_type);
}
}

bool Framebuffer::SetPWMBits(uint8_t value) {
if (value < 1 || value > kBitPlanes)
return false;
Expand Down
14 changes: 8 additions & 6 deletions lib/led-matrix-c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,19 @@ struct RGBLedMatrix *led_matrix_create_from_options(
OPT_COPY_IF_SET(cols);
OPT_COPY_IF_SET(chain_length);
OPT_COPY_IF_SET(parallel);
OPT_COPY_IF_SET(multiplexing);
OPT_COPY_IF_SET(pwm_bits);
OPT_COPY_IF_SET(pwm_lsb_nanoseconds);
OPT_COPY_IF_SET(pwm_dither_bits);
OPT_COPY_IF_SET(brightness);
OPT_COPY_IF_SET(scan_mode);
OPT_COPY_IF_SET(row_address_type);
OPT_COPY_IF_SET(multiplexing);
OPT_COPY_IF_SET(disable_hardware_pulsing);
OPT_COPY_IF_SET(show_refresh_rate);
OPT_COPY_IF_SET(inverse_colors);
OPT_COPY_IF_SET(led_rgb_sequence);
OPT_COPY_IF_SET(pixel_mapper_config);
OPT_COPY_IF_SET(inverse_colors);
OPT_COPY_IF_SET(row_address_type);
OPT_COPY_IF_SET(panel_type);
#undef OPT_COPY_IF_SET
}

Expand All @@ -101,18 +102,19 @@ struct RGBLedMatrix *led_matrix_create_from_options(
ACTUAL_VALUE_BACK_TO_OPT(cols);
ACTUAL_VALUE_BACK_TO_OPT(chain_length);
ACTUAL_VALUE_BACK_TO_OPT(parallel);
ACTUAL_VALUE_BACK_TO_OPT(multiplexing);
ACTUAL_VALUE_BACK_TO_OPT(pwm_bits);
ACTUAL_VALUE_BACK_TO_OPT(pwm_lsb_nanoseconds);
ACTUAL_VALUE_BACK_TO_OPT(pwm_dither_bits);
ACTUAL_VALUE_BACK_TO_OPT(brightness);
ACTUAL_VALUE_BACK_TO_OPT(scan_mode);
ACTUAL_VALUE_BACK_TO_OPT(row_address_type);
ACTUAL_VALUE_BACK_TO_OPT(multiplexing);
ACTUAL_VALUE_BACK_TO_OPT(disable_hardware_pulsing);
ACTUAL_VALUE_BACK_TO_OPT(show_refresh_rate);
ACTUAL_VALUE_BACK_TO_OPT(inverse_colors);
ACTUAL_VALUE_BACK_TO_OPT(led_rgb_sequence);
ACTUAL_VALUE_BACK_TO_OPT(pixel_mapper_config);
ACTUAL_VALUE_BACK_TO_OPT(inverse_colors);
ACTUAL_VALUE_BACK_TO_OPT(row_address_type);
ACTUAL_VALUE_BACK_TO_OPT(panel_type);
#undef ACTUAL_VALUE_BACK_TO_OPT
}

Expand Down
5 changes: 4 additions & 1 deletion lib/led-matrix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ RGBMatrix::Options::Options() :
inverse_colors(false),
#endif
led_rgb_sequence("RGB"),
pixel_mapper_config(NULL)
pixel_mapper_config(NULL),
panel_type(NULL)
{
// Nothing to see here.
}
Expand All @@ -258,6 +259,7 @@ RGBMatrix::RGBMatrix(GPIO *io, const Options &options)
}

Framebuffer::InitHardwareMapping(params_.hardware_mapping);

active_ = CreateFrameCanvas();
Clear();
SetGPIO(io, true);
Expand Down Expand Up @@ -332,6 +334,7 @@ void RGBMatrix::SetGPIO(GPIO *io, bool start_thread) {
!params_.disable_hardware_pulsing,
params_.pwm_lsb_nanoseconds, params_.pwm_dither_bits,
params_.row_address_type);
Framebuffer::InitializePanels(io_, params_.panel_type, params_.cols);
}
if (start_thread) {
StartRefresh();
Expand Down
6 changes: 5 additions & 1 deletion lib/options-initialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ static bool FlagInit(int &argc, char **&argv,
if (ConsumeStringFlag("pixel-mapper", it, end,
&mopts->pixel_mapper_config, &err))
continue;
if (ConsumeStringFlag("panel-type", it, end,
&mopts->panel_type, &err))
continue;
if (ConsumeIntFlag("rows", it, end, &mopts->rows, &err))
continue;
if (ConsumeIntFlag("cols", it, end, &mopts->cols, &err))
Expand Down Expand Up @@ -396,7 +399,8 @@ void PrintMatrixFlags(FILE *out, const RGBMatrix::Options &d,
"(Default: %d)\n"
"\t--led-pwm-dither-bits=<0..2> : Time dithering of lower bits "
"(Default: 0)\n"
"\t--led-%shardware-pulse : %sse hardware pin-pulse generation.\n",
"\t--led-%shardware-pulse : %sse hardware pin-pulse generation.\n"
"\t--led-panel-type=<name> : Needed to initialize special panels. Supported: 'FM6126A'\n",
d.hardware_mapping,
d.rows, d.cols, d.chain_length, d.parallel,
(int) muxers.size(), CreateAvailableMultiplexString(muxers).c_str(),
Expand Down

0 comments on commit 7160a8a

Please sign in to comment.