Switch-and-LED Puzzle Box: Working Out How to Drive the LEDs from a Pico

I'm building a switch-and-LED project where flipping switches lights up LEDs, but where something also has to count the switches and turn other LEDs on or off — so an MCU is in the picture. I started a thread to ask whether I could cut down the pin count by leaning on the fact that the switch just needs to drive its own LED most of the time, which would free up about 10 GPIOs. The discussion that followed talked me out of that shortcut and into wiring the LEDs to GPIOs anyway, so I get animation and PWM control, and it introduced me to the RP2040's configurable GPIO drive strengths as a possible way to skip per-LED resistors. My current plan is to test on the bench, starting at the lowest drive strength and working up, with a small resistor in place as a safety net while I experiment.

The problem

The build has a set of switches, each with an LED next to it, plus other LEDs whose state depends on calculation rather than on a single switch. My opening question in the thread was about pin economy: since the switch really only needs to drive its adjacent LED most of the time — on when the switch is on, off when it's off — could I avoid giving each of those LEDs its own GPIO? That would save me roughly 10 GPIOs.

The catch, and the reason a purely passive switch-LED-resistor-in-series arrangement doesn't solve my problem, is that the other LEDs need calculations. Something has to count the switches and turn those other LEDs on or off. So an MCU is going in there regardless, which means the question isn't "MCU or no MCU" but "which LEDs actually need to reach the MCU".

Where I landed on pin count

I decided I might as well just connect the LEDs to the GPIOs. There are enough pins, and doing it that way means I can animate them. I'm still not certain whether all the LEDs need to go to the MCU or only some — my instinct is that the LEDs next to the switches don't have to. I'm also unsure whether an LED would actually turn on if the pin is configured as an input and I'm grounding it. But if I end up Charlieplexing, I might as well wire them all to the pins anyway, so that uncertainty may resolve itself.

Multiple LEDs need to be on at once — regularly all of them — so any scheme where only one LED is lit at a time has to rely on flickering them fast enough that it reads as continuous light.

The resistor-free idea

The most interesting thing to come out of the thread was that the RP2040 has selectable GPIO drive strengths — 2mA, 4mA, 8mA and 12mA settings, which aren't exact currents so much as low/medium/high/very high. The suggestion was that on a low drive strength the chip simply can't deliver 3.3V at higher currents, so if you overlay the RP2040's voltage/current behaviour (Figure 171 in the datasheet, with the pads control covered in section 5.5.3.5) against an LED's Vf/If curve and find a point where they intersect, you may land in a range where the LED turns on without burning out — no current-limiting resistor needed. This was presented explicitly as theory, untested by me, and likely sensitive to things like temperature. There's also a total current budget across all GPIO pins to respect.

My test plan

I'm going to set the drive strength to the lowest setting and work upwards from there, eyeballing the LED intensity rather than measuring it. While experimenting I'll keep a small resistor in circuit as a fail-safe, in case I leave the LED's safe range and it starts drawing more than the Pico can handle — it can always come out later once I know where the safe operating point is. I'm aware I can fry both the Pico and the LED doing this, and I've accepted that risk.

If the proof of concept works, the next thing to look at is Charlieplexing, where varying the duty cycle also gives me control over brightness.

References

  • RP2040 datasheet — Figure 171, and section 5.5.3.5 on the GPIO pads control
  • Raspberry Pi documentation on GPIO pads control: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio-pads-control