• Using three I2C buses on Raspberry Pi 4

    Chris Combs09/06/2021 at 02:06 0 comments

    (First light)

    I really like the IS31FL3733 i2c matrix controllers I'm using in this project, but they do have one limit that I ran into fairly quickly. You can only have 16 of them on one i2c bus. Due to the large numbers of displays in this project, I needed to use 48 of them. 

    It's possible to use a multiplexer to fit more devices on to a single bus. But there are other problems with so many devices on a single bus: bus capacitance begins to be a problem (can each device quickly overcome the increasing capacitance to drive the bus to ground in a timely manner? this takes more and more current), as does having enough bandwidth to update all of the displays at a reasonable framerate.

    I began to wonder about using multiple i2c buses. The Raspberry Pi 4 has device tree overlays that enable something like 6 buses total. I had used one extra bus in a recent project ("Madness Method"), but only in a low-bandwidth way; could I keep three buses constantly busy updating these displays? 

    I tried it out, enabling i2c3 and i2c4. This is done through adding extra dtoverlay lines to /boot/config.txt, following the templates here:

    https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/overlays/README

    In my case, I chose pins_4_5 for i2c3 and pins_6_7 for i2c4; having all the pins near each other made the board routing cleaner.

    dtparam=i2c_arm=on,i2c_arm_baudrate=800000
    
    dtoverlay=i2c3,pin_4_5,baudrate=800000
    
    dtoverlay=i2c4,pin_5_6,baudrate=800000 

    After the device tree overlays are set up, restarting the Pi causes /dev/i2c? entries to appear. The numbers matched up for me, though I've read others reporting that the bus numbers might not exactly match but were in the right order (example: i2c5 and 6 showing up as buses i2c3 and 4)

    A side note for i2c4 pins_6_7: Pin 7 can also be CE1 for the SPI0 bus. If you have a library, like RF24, that uses the bcm2835 library to initialize the SPI bus, it will grab 7 for CE1, even if you are using CE0. This led to timeouts on the i2c4 bus in my case. 

    Between the extra bus connections and my desire to add power conditioning (PTC fuse, capacitors, TVS+zener diodes) I realized I needed a support boars ("warm bath") for the Pi 4. Luckily, I had just designed a similar board for another recent project ("Subset"). I used this "camera host" board as the base and added connectors and supporting circuitry for i2c3 and i2c4. 

    One intricacy of using the IS31FL3733 is that it, mercifully, doesn't require any sort of external transistor or driver to handle typical LED matrices. But it needs a little headroom to switch, almost half a volt: 150mV on the current source side, 300mV on the current switch side. 

    It accepts a wide range of input voltages: 2.7-5.5V. If I were to power this chip with 3v3, I wouldn't be able to switch a 3.2V white LED. So I generally power these controllers with 5V. Even when the LEDs I'm using aren't white or blue, I like to have a little headroom, and using a higher voltage lets me pull a given wattage at a lower current, lowering heat build-up in my wires and boards. 

    The Pi uses 3v3 signaling, so it can't always communicate with a 5v i2c device reliably. On my "warm bath" board, I placed three assembly-configurable PCA9306 level converters (and, crucially, pull-ups) to bring the Pi's i2c levels up to 5v. The PCA9306 devices can perform up to 100MHz (not a typo), but anything more than a MHz takes some fairly dramatic pull-ups; in this project I ended up with around 523 ohms (1k on the board, 2k2 at two points at bus endpoints). 

    Once I had the host board ready to go, with three i2c buses, it was time to wire it up to the panels and start working out the power arrangements. More on this in my next update.

  • About the display panels

    Chris Combs09/02/2021 at 20:54 1 comment

    The seeds of this project started when I scored 500 "18:88" common-cathode new-old-stock LED displays on eBay. I think these were intended for clocks (that can't do 24-hour mode, boo). There doesn't seem to be much demand for these displays, so I got them for a song or two, plus shipping.

    They came in two fairly large, heavy boxes, which provided impetus for me to convert these boxes into something fancy I could hang on the wall instead of taking up storage space.

    Each of these HPDS-B05G displays is a through-hole component with four digits and a colon. The digits are each broken out to their own cathode pin. The segments in all four digits are connected together, so a given position is the same anode pin among all four digits. (The colon gets slightly different treatment, as it becomes a "DP" pin associated with digits 2 and 3, and the first digit only has two of the eight segments.) You're intended to scan through the displays: set all of the segments to a given digit's values, begin draining current through its cathode pin, and cycle through all four digits this way. Do this quickly enough and it appears seamless to our eyes.

    You can do this with most microcontrollers, which is perfectly nice and makes it easy enough, given enough pins, to get some nice blink goodness going. But I have done a few other projects with the ISSI IS31FL3733, which is a 12x16 LED current-controlled matrix driver that takes care of 8-bit PWM, overall brightness range, short detection, and other goodies. Having greyscale control of each of the segments is actually quite a lot of fun! So I decided to use this chip for my display panels in this project. I can just give it greyscale values and it makes the magic happen!

    The 12x16 (cathodes * anodes) arrangement of the chip aligns fairly well with the 4x8 arrangement of the matrices, letting me pack six displays into a neat panel, using 150 / 192 possible segments. I wired up two parallel "chains" of the HDSP-B05Gs, using CS0:7 for one chain's segments, and CS8:15 for the other. Then I wired together the anodes the other way, using SW0:3, SW4:7, SW8:11. This gives me 150 segments per panel (25 per 4-digit 18:88 panel, with independent colon dots and no decimal points.) If I'd had 8.8.8.8. or 88:88 panels, could've had more segments for "free."

    I cranked away on a Very Exciting Spreadsheet for a while. I wanted to have a display of a common aspect ratio, such as 4:3, 3:2, or 16:9, to make mastering the content easier. Measuring the aspect ratio of the physical devices and adding padding and such let me figure out the real size of the panels. With each panel packing 2-wide, 3-high of the 4-digit displays, it turned out to work well to have 6 panels wide, 8 panels tall, for a total digit dimension of 48x24 digits; believe it or not, this ends up being 4:3, with the heights of the digits taken into effect.

    I laid out some boards in Eagle, following in the footsteps of some similar boards done previously. This time I made sure to include lots of extra connectivity options--I used "Qwiic," JST-XH x 4, and some panel-edge connectors that can be cross-soldered across multiple boards. The JST-XH connectors ended up carrying the day here. 

    (Yes, autorouted.)

    This chip communicates over the I2C bus and can have one of 16 different addresses. "But there are 48 controllers!" I hear you thinking. Stay tuned for my next project post, about the joys of using multiple I2C buses on the Raspberry Pi 4 with new kernel hooks provided by device tree overlays.