SM16380SC on Pi: porting board707's DMD_STM32 config sequence into the SPWM fork

Hi, and @board707 in particular — this builds directly on your DMD_STM32 DMD_RGB_SM16380SH class, so I hope you don’t mind the direct question.

HARDWARE

  • Two chained 128x64 P2.5 modules, 320x160mm, SMD2121
  • Column driver SM16380SC, row driver 5368PS, HUB75E
  • Raspberry Pi 3B+, Adafruit RGB Matrix Bonnet (74AHCT125), so logic levels are correct 5V. Verified against the SM16380SC datasheet, which requires V_IH = 0.7 x VDD = 3.5 V and rules out driving the panel’s own 74HC245 input buffers directly from the Pi’s 3.3 V
  • Separate 5V/25A supply, common ground, no undervoltage, no thermal throttling, isolcpus/nohz_full/irqaffinity configured per the guide

SOFTWARE

kingdo9/rpi-rgb-led-matrix_pwm_experiment @ 5da13cb.

WHAT THE PANEL DOES

Horizontal geometry is correct across both panels, colours are correct, and the background is properly black. What never works is the row scan: demo -D14 (a single red pixel) lights a full-height column, so every row displays the same content.

All 66 register profiles produce byte-identical output. I verified the flag is genuinely applied: --led-spwm-register-config=999 is rejected with “must be 0, or in the runtime catalog range 1..66”, =40 starts normally, and Demo 15 stepping through profiles live shows no change whatsoever. So the chip latches none of them.

WHAT I FOUND IN DMD_STM32, AND WHAT I DID WITH IT

Reading DMD_SPWM_Driver.h, DMD_RGB_SM16380SH::load_config_regs():

send_vsync();                  // LAT high, 3 clocks
send_clocks(8);
send_latches(11);
send_clocks(8);
send_latches(14);
send_clocks(8);
send_to_allRGB(0x00aa, 5);     // unlock
send_to_allRGB(0x01aa, 5);     // unlock
send_to_RGB(conf_reg[r], 5);   // one config register per frame
send_to_allRGB(0x0055, 5);     // lock
send_to_allRGB(0x0155, 5);     // lock
send_clocks(8);

plus GCLK_NUM = 1 (against 138 for FM6353 and 74 for FM6363), and the 30-word register table with conf[0] = 0x200 | (nRows - 1).

That 0xAA/0x55 envelope looked like the missing piece: the fork emits LAT bursts of 3, 11 and 14 — the same commands — but sends its five register slots straight, with no unlock wrapper and no 8-clock gaps. That would explain 66 profiles producing identical output. I patched the fork to emit your exact sequence, one config register per frame, cycling through the 30 words. It compiles and runs, but the panel behaviour is unchanged.

THREE FINDINGS THAT MAY MATTER TO OTHERS ON THIS CHIP

  1. The fm6373 profile matches your SM16380 code; sm16380sh does not. Your code uses first OE 12, look-behind 16, row switch at 112, OE pulse 4, and init LAT bursts of 3-11-14. The fork’s fm6373 profile matches all of it. Its sm16380sh profile instead uses first OE 10, look-behind 28, and LAT bursts of only 3-14 — the 11 burst is missing. I had been using sm16380sh for weeks purely because of the name.

  2. OE cadence has to scale with the chip count. 8 chips x 16 bits = 128 clocks, which is exactly the 128-clock OE cadence and the 112 row switch, so a single 128-wide panel is self-aligned. With two chained panels there are 16 chips and a 256-clock block, and the fixed 112/128 parameters fall out of step. Raising SPWM_OE_DURING_UPLOAD_CLK_COUNT / AFTER to ~240 with --led-chain=2 was the difference between white noise and a clean black background with the image continuing across the seam between both panels. Your data_transfer() handles this naturally because clk_count free-runs and resets at 128 regardless of num_sect; the fork treats those numbers as fixed profile settings.

  3. The chip keeps its state between runs. The same command line gives different results depending on what ran before it — registers and SRAM survive. Any measurement is only meaningful after a panel power cycle. This invalidated several of my earlier observations before I noticed.

WHERE IT STILL FAILS

Row addressing. Neither --led-spwm-row-addr-type 0/1/2 nor a patch routing the stock library’s ABC-shift-register row setters (–led-row-addr-type=3/5) into the SPWM path changes it, tested from a clean power-up.

So: horizontal geometry correct across both panels, real black, correct colours — and no vertical scan.

QUESTIONS

  1. Does the SC variant use the same command sequence as the SH, or is the instruction encoding different between them?
  2. GCLK_NUM = 1 — is that one GCLK pulse per row, or per data packet? On the Pi the equivalent knob is SPWM_OE_CLK_LENGTH (OE-carried GCLK), and I want to be sure I’m mapping the right quantity.
  3. spwm_chip_init() sends one register per frame with delay(30). Is that 30 ms settling essential, or an artefact of the refresh loop?
  4. Is the vsync required before every config write, or only once?
  5. Your data path comment says the driver expects 16 bits per pixel = 12-14 grayscale + 2-4 dummy bits. Is the greyscale MSB position (gclk_bits = 13) something the panel must be told, or purely how the host packs data?
  6. Is a 5368PS row driver compatible with what your panel uses, or does the row-select transport differ?

Happy to run any test and to contribute the result back to the Pi fork, so other SM16380 users get support rather than another dead thread.