The boss wants to add some lighted pushbuttons to an aircraft-specific bezel, and I don’t want them to be hand-wired forever. But each cluster of lights is physically isolated from the main processor board, and I don’t have much space. So I’d like to drive the LEDs and read the buttons with as few parts as possible, and I’d like to communicate reliably over a few inches of ribbon cable. Also, I’d like current control over the LEDs, which is my usual modus operandi these days. (There are two clusters: one has two lighted buttons, the other has four.)
I could just stick a Cypress processor on each board, I’ll have lots of control. But even the QFN-56 isn’t as small as I’d like. It’s square, and a rectangular shape might be “skinny” enough to fit where a square of the same area may not. Also, no current control. Also, the Cypress part isn’t very good at driving things.
A few years ago, before I started working with the TLC5929 and TLC5923, I’d discovered an I2C-connected part that had global current control, and global and individual PWM control, of 16 LED outputs: the TLC59116. I’d started to design it — or at least, thought-experiment it — into several projects I had going at the time. In the end, I abandoned it. But it occurred to me that I could use four outputs for the LEDs, and then four more as multiplexer drivers; I could use one spare I/O pin to read the results, two pins for the protocol, plus power and ground.
To cut this down from epic proportions: after several weeks of design, testing, experimentation and one online forum conversaion with a TI engineer, I’ve got a working design. But I’m not multiplexing the buttons as I originally thought of.
The problem with multiplexing the buttons is that once I sent a message to change the outputs, I’d have to wait for the message to travel and be acknowledged. The delay isn’t the problem so much as linking the multiplex read with the end of the transmission, especially given that other transmissions would be happening. Actually, in retrospect it wouldn’t be that big of a deal, especially since I ended up with a considerable amount of the work happening in a state machine anyway. But I found a solution I like better.
This part includes a set of error bits: one per output. For each output that is active (trying to drive an LED or other load), the corresponding bit tells whether the output is in thermal overload or has no load. Trying to overload the output has issues I shouldn’t even have to begin to tell you, starting with the fact that I probably won’t be driving the actual LEDs hard enough for the button outputs to overload even across a dead short. (…This was actually tested until the TI engineer figured out what I was trying to do.) But the absence of a load? That I can work with.
The bit turns on if a) the output is on and b) the output has a reasonable load. It turns off if there’s no load. The no-load error condition is self-clearing, so I can simply poll the part. Since I can read up to all 16 error bits with a single read, I can simply read the status over and over as quickly as possible. Which turns out to be something over 600 times per second (assuming two connected boards), giving an opportunity to do some debouncing.
Turns out I’ll also want control over the TLC59116 reset lines; if the I2C bus gets locked up I want to be able to clear it. So that extra I/O pin is useful, but not as a multiplex input.
It was a lot of work, and finishing it will be even more, but this is a definite win. Also, the part comes in an SOP package, and I arranged my resources such at it left 8 pins (4 on each side) free at one end of the chip. Means it won’t need traces there, giving a little more room.