adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.12k stars 1.22k forks source link

W55RP20 Support Requirements #9747

Open min-hs opened 4 weeks ago

min-hs commented 4 weeks ago

Our engineers have made initial progress in developing a driver for the W55RP20, but we've encountered a few difficulties that we would like to address with your team. Below is a brief overview of the situation:

The W55RP20 is a SiP project that integrates the RP2040 and W5500 in one chip. Internally, the dies are connected via general GPIO pins, not the typical SPI pins. As a result, a PIO program is needed to configure these pins for SPI communication.

Our engineers then decided to start from scratch, writing a PIO program and general code to initialize the W5500 through registers. They were able to create a basic loopback server in standalone mode. While this solution works as an alternative, we thought about the possibility of creating a new CHIP_VARIANT for rp2 CHIP_FAMILY. Given our limited resources, we thought of collaboration with Adafruit to further develop the driver.

The link below is to a WIZNet PIO example we created. https://github.com/WIZnet-ioNIC/WIZnet-ioNIC-Circuitpython

dhalbert commented 1 week ago

There are PIO SPI examples here: https://github.com/raspberrypi/pico-examples/tree/master/spi, but it seems like you are well along in your PIO SPI implementation.

I'm guessing that you had to choose the pins you did due to limitations of the placement of the bonding wires between the chips. Is that correct?

While this solution works as an alternative, we thought about the possibility of creating a new CHIP_VARIANT for rp2 CHIP_FAMILY.

I am not sure what you mean by this. The PIO SPI could be separated out, and then the W5500 functionality could be done mostly in a library and in device-independent code. For instance, see https://github.com/adafruit/Adafruit_CircuitPython_Wiznet5k

min-hs commented 1 week ago

Yes, that's right. We are currently using PIO SPI due to wiring issues between the RP2040 and W5500.

I've currently made some similar to wiznet5k to control the W5500 with PIO SPI instead of busio.SPI, but I'm having trouble getting it to work with different socketpools, dhcp, dns, and other protocols.

Also, if I do this, I would like to discuss with you how to utilize the W55RP20 library from adafruit to make it available to users in the future. https://github.com/WIZnet-ioNIC/WIZnet-ioNIC-Circuitpython

anecdata commented 6 days ago

I'm sure I'm oversimplifying several things, but bitbangio works with these pins (even ssl), so it seems like if PIO could make the pins look like SPI, the existing adafruit_circuitpython_wiznet5k driver library should work?

dhalbert commented 6 days ago

I think the q would be the SPI speed for bitbangio.

anecdata commented 6 days ago

Yes, I was mainly suggesting PIO SPI as a possible transparent alternate to SPI (or bitbangio SPI), not sure if that's possible.

BTW, I have these boards and could do some speed comparisons, but could use direction on code (and URL or what to serve) to test effectively.

dhalbert commented 6 days ago

I don't have time to look at this in detail at the moment, but here's what I was thinking of:

  1. Refactor https://github.com/WIZnet-ioNIC/WIZnet-ioNIC-Circuitpython slightly so that the PIO SPI is a separate class that has an API like busio.SPI, so that it can be just passed in to the Wiznet driver. PIO SPI could even be a separate library totally.
  2. Look at the Wiznet code in that repo and see how it compares to https://github.com/adafruit/Adafruit_CircuitPython_Wiznet5k. I don't know at all -- I haven't taken a look. If it's different, that may point to why @min-hs says they are having trouble.
  3. Are there things in WIZnet-ioNIC that we could adopt in our driver? Or is WIZnet-ioNIC a better driver, once it's debugged?
anecdata commented 6 days ago

Re: (1.), I get as far as AttributeError: 'StateMachine' object has no attribute 'try_lock' when trying the PIO SPI with the existing driver on the W55RP20, which I interpret to mean that the PIO SPI implementation could possibly be beefed up to be compatible enough for the existing driver. But perhaps min-hs has already been down that road.

min-hs commented 5 days ago

(1) I think it would be great to have it as a separate library, or you could create a separate class called ioNIC in the existing adafruit_wiznet5k driver.

(2) Currently in that repo, the W5500 is controlled by SPI using busio. The W55RP20 can't use hardware SPI due to pin issues, so we use rp2pio to drive the W5500 since it uses SPI PIO.

(3) It is not a better driver, but it is also a packaged chip that integrates RP2040 and W5500, and it is a solution that many users have responded to.

@anecdata Is the error on the rp2pio internal statemachine side in the link below? https://github.com/WIZnet-ioNIC/WIZnet-ioNIC-Circuitpython

anecdata commented 5 days ago

@min-hs I tried the WIZnet-ioNIC code and example and of course that worked fine. The exception was when I tried to naively use the statemachine as SPI with the existing circuitpython WIZnet library.

But conceivably to Dan's point and yours, someone who knows what they are doing could construct a more SPI-compatible class or library using the statemachine. I didn't get far enough or do a thorough audit of the methods needed (read, write, etc), but try_lock and unlock do seem to be needed.

min-hs commented 5 days ago

Thank you so much for your help. @anecdata I'm not sure how I'm supposed to use try_lock and unlock, can you give me an example or explanation of how to use them?

dhalbert commented 5 days ago

(2) Currently in that repo, the W5500 is controlled by SPI using busio. The W55RP20 can't use hardware SPI due to pin issues, so we use rp2pio to drive the W5500 since it uses SPI PIO.

Yes, I am saying you could refactor the library so it's using an SPI interface in the abstract, instead of knowing that it must use the "soft" SPI provided by your PIO program. The driver does not need to know that it has to use PIO SPI. My understanding is that you are using it the same way you would use it if it were an external chip. Only the transport has changed slightly.

I'm not sure how I'm supposed to use try_lock and unlock, can you give me an example or explanation of how to use them?

See try_lock() and unlock() in https://docs.circuitpython.org/en/latest/shared-bindings/bitbangio/index.html#bitbangio.SPI. The SPI obect supports a lock so that it can't be used concurrently for more than one device without the two users cooperating around the lock. There is some discussion of that in this writeup of CircuitPython SPI: https://learn.adafruit.com/circuitpython-basics-i2c-and-spi/spi-devices

jepler commented 4 days ago

Something that I was discussing about this on Discord:

Both busio.SPI and rp2pio.StateMachine have read and write methods, they have different behaviors: SPI discards the "unwanted" side, while StateMachine retains it in a (small) FIFO. Thus, for a PIO SPI implementation to be compatible with busio.SPI, it will have to implement read and write both in terms of write_readinto, likely with some kind of dummy buffer of the right length for the unneeded half of the data. Without this, the first few bytes sent to write will work, but they'll stop being output once the 4-entry rxfifo fills (PIO program stalled at the push instruction) and then write will block once the 4-entry txfifo fills.