Two-sided display

I have 8 - 16x32 panels that I’ve arranged into a display 32x128 using the u-mapper. This is a single chain of 8 panels. What I’m trying to accomplish is to have a dual sided display of 32x64 on each side and then display the same data/image on each side. I’d like pretend that the display is 32x64 on one side and have whatever I write to that side show up on the other side. Strangely, when I lie and say the chain length is 4(not the actual 8) it’s almost what I want; the difference is that the second side is upside down. Thoughts/suggestions?

U-mapper will do the 2nd line upside down indeed.
If you are trying to get the exact same output, just wire the 2nd chain at the end of the first one, and use this patch. This will output the bits twice, so that they get shifted to your back panels and you get an exact copy image.

diff --git a/lib/framebuffer.cc b/lib/framebuffer.cc
index 70543b0..03c6eb6 100644
--- a/lib/framebuffer.cc
+++ b/lib/framebuffer.cc
@@ -558,10 +558,10 @@ static void InitFM6127(GPIO *io, const struct HardwareMapping &h, int columns) {
                                               int columns) {
   if (!panel_type || panel_type[0] == '\0') return;
   if (strncasecmp(panel_type, "fm6126", 6) == 0) {
-    InitFM6126(io, *hardware_mapping_, columns);
+    InitFM6126(io, *hardware_mapping_, columns*2);
   }
   else if (strncasecmp(panel_type, "fm6127", 6) == 0) {
-    InitFM6127(io, *hardware_mapping_, columns);
+    InitFM6127(io, *hardware_mapping_, columns*2);
   }
   // else if (strncasecmp(...))  // more init types
   else {
@@ -853,15 +853,17 @@ void Framebuffer::DumpToMatrix(GPIO *io, int pwm_low_bit) {
     // Rows can't be switched very quickly without ghosting, so we do the
     // full PWM of one row before switching rows.
     for (int b = start_bit; b < kBitPlanes; ++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 gpio_bits_t &out = *row_data++;
-        io->WriteMaskedBits(out, color_clk_mask);  // col + reset clock
-        io->SetBits(h.clock);               // Rising edge: clock color in.
+      for (int i = 0; i < 2; ++i) {  // Output the same stuff twice for 2nd panel
+        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 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);    // 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();
diff --git a/lib/led-matrix.cc b/lib/led-matrix.cc
index afa943d..b2403d1 100644
--- a/lib/led-matrix.cc
+++ b/lib/led-matrix.cc
@@ -622,6 +622,8 @@ RGBMatrix *RGBMatrix::CreateFromOptions(const RGBMatrix::Options &options,
     return NULL;
   }
 
+  fprintf(stderr, ">>>> Double Shift Enabled (slower) <<<<\n");
+
   // For the Pi4, we might need 2, maybe up to 4. Let's open up to 5.
   if (runtime_options.gpio_slowdown < 0 || runtime_options.gpio_slowdown > 5) {
     fprintf(stderr, "--led-slowdown-gpio=%d is outside usable range\n",