This is really helpful! thanks a bunch!
Question: you say you've been doing a lot of charlieplexing, I've been having a difficult time grasping the whole idea of coding around charlieplexing. Do you have a sketch or something I could study?
The simplest (useful) Charlieplex sketch I know of it Ben Brandt's - it's what I use for anything under 30 elements since it's just running around in a loop. It has limitations that keep it from scaling too well, but it's pretty clear how it's working:https://github.com/benbrandt22/TinyLife5
Effectively you define your port configuration in led_dir and led_out, then you can call light_led with which LED you want to light. But I usually use draw_frame to run over an array of LED brightnesses. So instead of drawing a 4x5 grid of LEDs, I have one running a Tiny85 using Asher Glick's charliecube arrangement in this code:https://github.com/pfriedel/TenMilSpire
..which isn't as well commented as it could be, but if you look at the main loop, the first case is pretty straightforward: It draws a random LED in a random color for 100 loops. It's entirely free from strict timing, so it's not too useful when you try to do things asynchronously, but for simple displays it's easy to get up and running.
Once I needed more asynchronous capability (where I can just fire drawing commands off into an array and an ISR handles keeping the display updated), I migrated to Jimmie Rodger's LoL Shield code. The simplest version that I have running is a 30 LED array that plays life and tells the time:https://github.com/pfriedel/SixByFiveplex
Fundamentally the changes from the Lol Shield product are mostly tied up in the ledMap definition in Charlieplexing.cpp. Each element of the array is the input and output pins for each LED position. If you look into the Rain function, that's a simple way of driving the array - make changes to world, call fade_to_next_frame() to switch active buffers.
The 110 LED arrays in the video are all using the logical extension of the 30 LED code, just tweaked for memory utilization - the LoL Shield code tends to allocate way more memory than it needs, which limits what you can do with a 328:https://github.com/pfriedel/OneTenClock
...which still needs to be cleaned up, but it's at that stable point where debugging it is frustrating since errors creep in after running for an hour.
Hope this helps!