Close

90's LED Matrix -- Weird Decisions

A project log for Z80 Reverse-Engineering And Hacking Adventures

What else can I say?

eric-hertzEric Hertz 08/30/2023 at 12:510 Comments

I've acquired and am rebraining/repurposing a Red/Green LED matrix sign, made in the early-mid 1990's with a densely-peripheralled Z80 processor board (which, later, might be fun to also repurpose? Sorry @ziggurat29, I haven't gotten you those ROMs, yet!)

The matrix boards are pretty simple: 74HC164 serial-in parallel-out shift-registers drive the columns via NPN darlington arrays. A couple simple 3in-8out demultiplexers choose the row, and drive some big ol' discrete PNPs. Pretty simple to interface.

Each board is a matrix of 45x16 bicolor LEDs, and as I understand, it had four of these boards, and one 45x16 red-only board at the end. So, we're talking some 400+ columns need to be shifted-in, then the row gets enabled. Their software design (which I didn't test before designing mine near identically, I guess the hardware is a huge determining factor) drives it at 60Hz. It loads all the pixels at about 4MHz shift-clock, then stops shifting and enables a row, briefly. Each row, then, is lit for about 0.7ms, while shifting takes about 0.1ms.

Note that shifting that much data that quickly is no easy task for a z80, so the CPU board looks like it has dedicated shift-registers (and associated clock timers) as well as RAM-addressing circuitry. Really, quite a lot of circuitry.

Interestingly, they used one 74HC4094 in place of the last '164 on each board, apparently for the sole purpose of resynchronizing the clock and data signals over such long distances(?).

An interesting feature of the 4094 is that it has a second set of latches on the shift-register outputs, thus if they'd have used 4094s instead of all the 164s, they could've shifted-in data *while* displaying the previous row.

I found this intriguing-enough to consider desoldering the 164s and replacing them all with 4094s... and, to be honest, right now I can't exactly recall *why*, because I came across a much bigger discovery while running through this mental exercise...

(Oh, I think it had something to do with the annoying flicker at 60Hz... I thought maybe If I latched while shifting, then bumped it up to 120Hz, maybe 240, by decreasing each row's on-time, the 4094s' built in latches would allow for its not dimming dramatically by not increasing the ratio of load/off-time vs on-time).

But I discovered something far more dramatic, in terms of improvement than just that...

I'd first looked into investing in 74HC4094's, to handle the 4MHz clocking... They're not too bad, maybe 30bux to replace all the 164's. Would be worth it to get rid of the flicker!

So keeping on with the redesign mental exercise, I pondered *how* to plug these new 16pin chips in the densely-packed 14pin spaces... Turns out the pinouts are *very* similar, requiring only two bodge wires, which also happen to be the same signals, from the same sources, on all the chips. (Latch-Strobe, and Shift-Clock) so would be very easy to bodge half-deadbug-style by just bending up two pins. OE is active high and in the 164's V+ position, so soldering the 4094's pin15 to pin16 takes care of the "overhang" where there are no PCB pads for the larger chip... Also, it turns out the 164's plastic cases are actually the same length as the 4094's, despite the extra two pins, so there is enough space between the chips for the extra pins! It's coming together quite smoothly.

...

But we still haven't gotten to the kicker...

I'd also thought it might be nice to add an extra data bit, two for each color (red and green), in my design's framebuffer... Doing so at 60Hz would just make the flicker worse for the 33% and 66% shades, but a higher refresh rate would probably keep it pretty smooth. 

But we have another problem... with a 16MHz AVR, and 4MHz SPI, we've basically got zero time to process anything other than loading the next SPI data byte while the previous is shifted-out. (especially since I bumped it up to 8MHz, despite being a bit uncomfortable with such speeds over several feet, unshielded). So, during the time, currently, when it's shifting in a row's worth of pixels, the AVR basically can't do /anything/ else... and that amount of time is far longer than two bytes sent from a PC via the UART... which means allowing interrupts is necessary *during* row-shifting, even though doing-so would make flicker even worse (and, now, inconsistant, which might be a problem for folk with epelepsy?) But, /where/ such delays are allowed is also rather important, because they *really* went out-of-spec with overdriving these LEDs... I can't recall, but I think it was something like absolute max 90mA at some tiny percentage duty-cycle, and they're doing 140mA at 1/16th. So, I don't want a slew of UART interrupts extending that any further! These are just tiny little LEDs, after all!

So, then, if I allowed interrupts when loading row data, the row would dim and/or the timing would shift... Not ideal. But if I don't, then UART data would be lost. Not an option.

So another aspect of using the 4094s' latches would be that I could just set some arbitrary amount of time to display each row, via timer peripheral, and then the actual row-loading could be interrupted any time, as long as the loading process is much shorter than the displaying time.

Great!

No, I mean, it gets even better...

I planned to use 74HC4094's which are rated for 20MHz... but then I looked in my stock to see if I could experiment before/without placing an order... and... a whole board's worth of CD4094's... which... are only rated to 1.25MHz (4000-series is SLOW!)...

But then, it occurred to me to math... and it turns out that the 4094's latch means I could do 200Hz /no problem/, even at 1MHz SPI. In fact, if I only do one panel (90 col) per AVR I can do nearly 200Hz with an SPI divisor of 64?! That means each bit takes 64 CPU clocks, that means each byte is 512 CPU clocks, meaning I can use an SPI-interrupt to load the next byte, no problem, and still improve the refresh rate dramatically, and use regular interrupts [UART, etc.] relatively freely, *and* even process main loops *while* loading row data! All this by LOWERING the SPI row-upload rate, and using *slower* components, which were surely available cheaper than those used when this was designed. And, I mean... AVRs are significantly faster than Z80s, and have significantly more inbuilt peripherals than this custom CPU board has customly designed on it... Surely, if they'd've used the 4094's instead of '164's, they could've reduced quite a bit of the precision timing and custom circuitry needed on the CPU board... And reduced flickering, and increased duty-cycle (so reduce the huge surpassing of abs-max for the same brightness)... Heh. And they even *did* use the chip that would've eneabled all this, just in a weird way that didn't even take advantage of its best feature. Heh. Weird.

Sometimes, I guess, slower is faster? (Oh, I just saw them say this on NASA's livestream of the launch. Hah!)

I think I'll put in sockets, and leave the bodgery to deadbugging bent pins, then it can have the 164's reinserted, for posterity.

Discussions