What's best way to determine Pimoroni product from MicroPython?

What’s the best way to determine which Pimoroni product a MicroPython program is running on? I was thinking of adapting the code in Instructables: Battery-Powered Digital Picture Frame Using Pimoroni Inky Frame for the new, smaller 4 inch Inky Frame.

If there’s not a general approach I’ll probably just use get_bounds() like pimoroni-pico/inky_frame_placekitten.py at main · pimoroni/pimoroni-pico · GitHub to retrieve the resolution of the Inky Frame’s screen - is that a reasonable approach?

If you’re trying to pick which display to use to initialize the the pico graphic library I don’t think that will work, since the initalizer sets the size.

if you’re just looking to determine which one it is after initialization, then that would work fine.

AFAICT the only difference between the two is the display itself, so unless there’s some identifier in the board builtin library, the only hope for the first case would be to directly query the display through SPI? I’m still new to the hardware game, so unsure what information it might pass back. I’m afraid you’ll need a more experienced mind than mine to direct you there.

I was curious since I have a project or two that could use automated selection of imports so I peeked at the SPI class in the adafruit library, didn’t see anything obviously useful.

however, assuming you have both, or can ask someone who owns one of the other ones, I’d try

import board
print( board.board_id )

or

import os
print( os.uname().machine )

one of those might give a different name for each device, and I think would be the canonical way to determine which it is.

but as I mentioned before, if you’re just wanting to know after it’s already initialized, grabbing the dimensions is perfectly acceptable (especially since I’m guessing you’re using it to size the images sent), and potentially saves an import

For the specific case of the Inky Frames there’s a hardware difference between 5.7" and 4" shown on schematic, latter has a 10k pull up on SWITCH_LATCH and a note saying

Pull-up on SWITCH_LATCH is used to detect the display size (4.0")

I’d imagine a battle between weak (50-80) internal pull down and that 10k is used to distinguish between the two. That doesn’t sound like a very flexible approach for future variations but it’s better than nothing.

Deserves a bit more testing but this seems to work to differentiate between the three models of the Inky Frame. I’d prefer it was in a library and reviewed to ensure it’s safe wrt raising what might be the select line on the PSRAM.

### Do a pull down test of I2C_INT / PSRAM_CS (GP3)
i2c_int_psram_cs_input = Pin(IF_I2C_INT_PSRAM_CS_PIN, Pin.IN, pull=Pin.PULL_DOWN)
i2c_int_psram_cs_state = i2c_int_psram_cs_input.value()
### Reset the pin to input for I2C_INT or to output for PSRAM_CS
if i2c_int_psram_cs_state:
    _ = Pin(IF_I2C_INT_PSRAM_CS_PIN, Pin.IN, pull=None)
else:
    _ = Pin(IF_I2C_INT_PSRAM_CS_PIN, Pin.OUT, value=0)

### Do a pull down test of SR_LATCH (GP9)
sr_latch_input = Pin(inky_frame.SR_LATCH, Pin.IN, pull=Pin.PULL_DOWN)
sr_latch_state = sr_latch_input.value()
### Reset the pin state to a low output
_ = Pin(inky_frame.SR_LATCH, Pin.OUT, value=0)

if sr_latch_state:
    from picographics import DISPLAY_INKY_FRAME_4 as DISPLAY  ### 4.0"
elif not i2c_int_psram_cs_state:
    from picographics import DISPLAY_INKY_FRAME_7 as DISPLAY  ### 7.3"
else:
    from picographics import DISPLAY_INKY_FRAME as DISPLAY    ### 5.7"
1 Like
NameError: name 'IF_I2C_INT_PSRAM_CS_PIN' isn't defined

What pin to I need to set it to?

image

Is that Pin(9)?

image

Instructions unclear. 😝

I have to admit I don’t understand what this var name is trying to communicate, but if I just follow your comment (pin 3) and clean up the code a bit, I end up with this:

def get_display():
    I2C_INT = 3
    def get_state(pin):
        pin_input = Pin(pin, Pin.IN, pull=Pin.PULL_DOWN)
        pin_state = pin_input.value()
        Pin(pin, Pin.IN, pull=None) if pin_state and pin == I2C_INT else Pin(pin, Pin.OUT, value=0)
        return pin_state

    return (
        11 if get_state(inky.SR_LATCH) else
        22 if not get_state(I2C_INT) else
        10
    )

It works for Inky Frame 4.0" and 5.7". If you forget to put the SR_LATCH state down, the buttons stop functioning. I don’t understand what actually happens, I just refactored the code a bit because I need the bytes.

The DISPLAY is just a hardcoded number, nothing fancy. I hope they are relatively static across builds.

The full code is in the article - glad it was helpful in the end.

The IF_I2C_INT_PSRAM_CS_PIN (GPIO 3) is Inky Frame and I2C_INT on 4.0".and 5.7" but it’s PSRAM_CS on 7.3" as that has to have additional PSRAM to cope with the memory needed for higher resolution screen.

It would be nice if Pimoroni provided library functions for either Inky Frame or all their boards and periperhals to identify them. Latter is a bit of a gap in a lot of the hobbyist world.

Hey thanks for the links. I hadn’t seen those. These articles are very helpful.

The IF_I2C_INT_PSRAM_CS_PIN (GPIO 3) is I nky F rame and I2C_INT on 4.0".and 5.7" but it’s PSRAM_CS on 7.3"

Ah thank you. But what is it for though? And come they can safely be used for two purposes without causing problems? I2C_INT? It’s an interrupt? PSRAM_CS, it’s a chip select? And, not related to this topic but in the same category: GPIO 25 can read the battery charge level but it’s the WLAN SPI. But only one or the other. I would be too afraid to attempt to use these pins because I don’t understand the implications, had it not been for people like yourself showing me the empirical evidence to illustrate it appears to be safe to use in this way. :D

Anyway, not new to Python, but new to Pico and Pimoroni. I missed these type of explanations in the getting started guides.