Charlie's (LED) Angel
I don't know what embedded systems programming will be like in 100 years. But I am convinced of one thing: It will, as it does today, involve trying to get more of something out of less of something else.
Let me explain. The first system I got paid to design was a CPU board based around the 6805 that went into a leak detection system. Since the government was paying us to do the board, we wanted to make it general purpose enough to reuse it (which we did). The problem is that the EPROM and RAM chips available back then were positively minuscule. The 6805's address space was only good for about 8K anyway (although later versions of the part could sort of address more).
We wound up spending a lot of time trying to shave some code down by 9 or 10 bytes so it would fit in the 4K main EPROM. Oh, and to make things easier, you could only read from the EPROM. If you wrote, you actually addressed an LCD display. We figured if you timed it right, you never actually needed to read from the display. That wasn't the only multiplexing going on. One of the part's I/O bits selected between another 4K EPROM (the math library) and a UART. So you could talk over the modem, or do math, but not both at the same time.
Today, cramming things into memory isn't as common as it used to be since many parts have lots of memory onboard and most have no provision for external memory. So you pick a part that will hold what you want to do and that's usually sufficient. But the fact that there is little room for I/O expansion is what really drives most of my cramming these days. I'm always on the lookout for a way to get more inputs or outputs on fewer pins.
Of course, there are the bus answers. You can use I2C, Dallas/Maxim OneWire, or SPI to talk to "smart devices" on the bus. That's fine, if you have smart devices. But what about something simple like plain old-fashioned LEDs?
The common solution, of course, is to multiplex. The 7-segment displays in calculators and clocks are usually done this way. You drive all the digits together (7 outputs) and then have one output per digit that you make active to enable any particular digit. If you activate each digit often enough, your eye will see a slightly dimmer display but will still think all the digits are on at once. So for, say, 4 7-segment displays you need 7+4=11 output pins.
Can you do better? If you can turn output pins off (not to zero, but really off), the answer is yes. Most modern microcontrollers can set a pin high, low, or set the pin as an input. If the input state is effectively "off" you can use this capability to drive more LEDs (or other outputs). The technique is called "charlieplexing", ostensibly named after Charlie Allen at Maxim who appears to be the first to publish such a scheme.
Consider two LEDs back to back. You can even buy two-color LEDs like this. Say one LED is X and the other is Y. The anode of X and the cathode of Y connect to a port; call it A. Then the cathode of Y and the anode of X connect to port B.
This arrangement means that if you place pin A high and pin B low, one LED will light. If you reverse the pins (that is, put pin A low and pin B high) the other LED will light. Big deal, right? You could just use the two pins to light the two LEDs independently, so what's the benefit?
The benefit is when you add another pin and the ability to set any of the pins to one of three states: high, low, or input. Consider this schematic:
And this truth table (where H=high, L=Low, and I=Input, and * indicates a lit LED)
So with only 3 pins, you can control 6 LEDs. In theory, N pins can control up to N(N-1) outputs. Of course, if you want more than one on at a time, you'll need to refresh them.
You can use the same scheme to multiplex input signals. You can place a switch (or something that looks like a switch) in series with each LED. You can read more about charlieplexing on the Maxim website.
What's your favorite trick to save memory or I/O pins? Drop me a note and let me know.