Skip to content

Fast(ish) special purpose bitbang spi over i2c #8401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 18, 2023

Conversation

jepler
Copy link

@jepler jepler commented Sep 14, 2023

with the i2c bus operating at 400kHz this achieves a 4.8kHz SPI clock rate which could be worse.

It accepts the same style of init sequence as displayio.

tested by scoping the pins on the espressif lcd dev kit with a dummy init sequence:

Initialization exercise code
import busio, microcontroller, dotclockframebuffer
expander_addr = 32
init_sequence=b"\x55\3\xaa\xff\x00" * 100

bus = busio.I2C(microcontroller.pin.GPIO18, microcontroller.pin.GPIO8, frequency=400_000)

if not bus.try_lock():
    raise RuntimeError("Bus already locked")
bus.writeto(expander_addr, b"\3\xf1")
bus.writeto(expander_addr, b"\2\0")
bus.unlock()

dotclockframebuffer.ioexpander_send_init_sequence(
    bus=bus,
    i2c_address=expander_addr, 
    gpio_address=1,
    gpio_data_len=1,
    gpio_data=0xff,
    cs_bit=1,
    mosi_bit=3,
    clk_bit=2,
    init_sequence=init_sequence)

image

I'm not 100% thrilled with the naming & placement of this function so please feel free to bikeshed that.

with the i2c bus operating at 400kHz this achieves a 4.8kHz SPI clock
rate which could be worse.

It accepts the same style of init sequence as displayio.

tested by scoping the pins on the espressif lcd dev kit with a dummy init sequence:
```python
dotclockframebuffer.ioexpander_send_init_sequence(
    bus=bus,
    i2c_address=expander_addr,
    gpio_address=1,
    gpio_data_len=1,
    gpio_data=0xff,
    cs_bit=1,
    mosi_bit=3,
    clk_bit=2,
    init_sequence=init_sequence)
```
Before, incorrect use when calling a core function would just say
"extra keyword arguments given"; now, it will name the argument:

```python
>>> Synthesizer(bad_kwarg="boo")
TypeError: unexpected keyword argument 'bad_kwarg'
```
Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the main reason to have this natively is for boards with native displays? It's a bit weird that there isn't one using it. I wonder if it should only be made available internally.

From Python can't we do IOExpander DigitalInOuts + bitbangio?

@jepler
Copy link
Author

jepler commented Sep 15, 2023

Yes, this is needed to support boards with built-in displays like the esp32s3 lcd dev kit. but if you like I can gather numbers showing it's also a good deal faster than a pure Python bitbang spi-over-i2c. (even so, it's not fast; each SPI bit is 2 I2C transactions with 24 bits each, so the absolute maximum with a 100kHz I2C bus is about 2kHz and in practice it's slower; the 400kHz I2C bus only got to 4.8kHz SPI bit rate)

@jepler
Copy link
Author

jepler commented Sep 15, 2023

I can rebase out this commit if you like: a8b81ce

@tannewt
Copy link
Member

tannewt commented Sep 18, 2023

We discussed this in the weeds today. This is a good interim solution until we decide how to use abstract DigitalInOut-like objects with native bitbangio for native IOExpander support.

@tannewt tannewt merged commit e39fbf1 into adafruit:main Sep 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants