Skip to content
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

Supporting the CY7C65215 #3

Open
runger1101001 opened this issue Nov 5, 2024 · 9 comments
Open

Supporting the CY7C65215 #3

runger1101001 opened this issue Nov 5, 2024 · 9 comments

Comments

@runger1101001
Copy link

Thank you for your excellent work on this library.
In your readme you write:

However, in my experience so far, they are easier to work with and simpler to design your circuit board around. In particular, they do not need an external EEPROM, and they are much better documented on the electrical side. Why the industry still prefers the FTDI chips is... something of a mystery to me at this point.

I agree very much with this statement. I think perhaps the reason the FT2232H is still widely used, is that is has better software support. Your library may go a long way to change that.

I'm trying to add support for the CY7C65215 chips, the dual channel versions of these chips. Compared to the FT2232H this chip also offers 2 serial channels configurable as either UART, SPI or I2C, but needs far fewer external components to support it, and comes in a smaller package at half the price.

In terms of the code, at the moment it does not work to connect to these chips. To get my local version to connect, I needed to change the list_devices function in cy_scb_context.py.

There are significant differences to the USB device for the 2-channel version:

  1. The PID is a different one. It seems to be 0x0005 or 0x0007
  2. the CY7C65215 has 4 USB Interfaces when configured with 1 CDC UART and 1 SPI. I have to check different configurations, but presumably there is always one extra interface since it has 2 SCBs.
  3. the interface order seems to be: 0 - control, 1 - SCB1, 2 - SCB2, 3 - MGR
  4. the interfaces have the same classes and subclasses, but the endpoints are a little different: the endpoints for the SCBs in Vendor mode have different addresses. Instead of 0x01, 0x82 and 0x83 it is 0x04, 0x85 and 0x86.
  5. After modifying the checks in list_devices accordingly, it connects to my CY7C65215 successfully.

I'm happy to submit these changes as a PR, but I am uncertain regarding the best way to proceed.

What is the purpose of all these checks? Are you trying to recognise the device based on its interface and endpoint configuration? Why not trust the user-supplied PID values?

How to deal with the fact that there could be 2x UART or 2x SPI, etc? The CLI has the --scb option, but the SCBContext does not seem to take it into account?

@multiplemonomials
Copy link

Yeah frankly I'm shocked at how bad everything about the FT232H is. The example circuit uses a bajillion additional components and the datasheet is awful -- low res screenshots of example circuits, super unclear pin descriptions, you name it! Plus, when I tried it on my custom PCB I wasn't able to get it booting after like a month of on and off debugging. So I switched to Cypress parts, never to look back.

Yeah, unfortunately this driver isn't totally set up for the dual channel devices yet. I realized that when I was writing it but didn't really have time to go back and add support. At present I don't actually have a dual channel device to test with, though I might pick one up at some point.

The first thing we need to fix is the USB device scanning code in cy_scb_context.py, as you discovered. This code exists because these chips can have arbitrary VID/PID values, and I wanted a way to reliably detect them just based on their USB structure.

So that I can update the detection code, could you run this detection script on your PC with the CY7C65215 attached? I will probably need one run with it in I2C, SPI, and UART modes. That should give me enough info to update the detection code. Alternately you're welcome to submit a patch if you are confident making the needed mods.

After we fix that, the next step will be to update the driver code to properly distinguish SCB1 and SCB2. Currently some places are aware of the difference but other places aren't. We will probably need to add some new command line options as well. Last but not least, we will have to update the configuration code to be dual channel aware. I think the dual channel devices must use a somewhat different configuration format, so that will probably require some reverse engineering of the "set settings with USCU, then dump the config block" variety.

@runger1101001
Copy link
Author

I've actually made a bit of progress which I need to clean up and add to my PR...

I've also started working on a flash.py CLI tool, since I think writing to flash memories or FPGAs will be a primary use case. The current SPI code in the cy_serial_cli is good for testing but not enough to properly interact with flash memories. So I'm trying to add a small tool that will speak to CFI-conformant devices and allow the user to read/write/erase the chips.

I'll try to run the detection later today, or latest by end of week - I'm killer busy at the moment :-/

@multiplemonomials
Copy link

That would be awesome, thank you!

@runger1101001
Copy link
Author

runger1101001 commented Nov 27, 2024

Sorry for the delay... very busy at the moment, it took a while to fit this in. But I've finally done some more work on my PR and have checked the USB device infos for you now...

For the screenshot and device scan below I had things configured with one CDC UART interface and one SPI interface on the two SCBs:

USBProber Screengrab:

image

Output of scan_device_tree.py:

- Device: 04b4:0007, Cypress Semiconductor USB-Serial (Dual Channel), SerNo: None
---> Cfg: Num Interfaces: 4, Identifier: 1, Attributes: 0xa0
    ---> Interface 0
        ---> Alternate settings 0: Num Endpoints: 1, Class and SubClass: (0x02, 0x02), Protocol: 1
            ---> Endpoint 0x83: Direction: Dev-To-Host, Type: Interrupt
    ---> Interface 1
        ---> Alternate settings 0: Num Endpoints: 2, Class and SubClass: (0x0a, 0x00), Protocol: 0
            ---> Endpoint 0x01: Direction: Host-To-Dev, Type: Bulk
            ---> Endpoint 0x82: Direction: Dev-To-Host, Type: Bulk
    ---> Interface 2
        ---> Alternate settings 0: Num Endpoints: 3, Class and SubClass: (0xff, 0x02), Protocol: 0
            ---> Endpoint 0x04: Direction: Host-To-Dev, Type: Bulk
            ---> Endpoint 0x85: Direction: Dev-To-Host, Type: Bulk
            ---> Endpoint 0x86: Direction: Dev-To-Host, Type: Interrupt
    ---> Interface 3
        ---> Alternate settings 0: Num Endpoints: 0, Class and SubClass: (0xff, 0x05), Protocol: 0

I have committed the changes you requested to my fork, and the PR has updated.
I've also committed changes to the cy_scb_context regarding the device identification. Of course, my problem is that I don't have the other devices to compare :-) but hopefully together we will get there.

I think I'm part of the way towards a solution.

The changes I have made are fundamentally this:

  • the detection code was too geared towards the single SBC chips. With the dual channel chips, you can have multiple serial/spi/i2c devices, with CDC or vendor mode, etc.
  • so the approach I took is to categorise each interface as one of the types: CDC, VENDOR UART, SPI, I2C, MFG, CDC_DATA, JTAG
  • after checking each interface type, we assign the ones we identified to the DiscoveredDevice. If the combination of stuff we found doesn't make sense, we skip the device

What's not yet working?

  • multiple interfaces of the same type (e.g. 2x SPI, 2x CDC). but its ok if you have for example 1xSPI and 1xCDC
  • the DiscoveredDevice.curr_cy_type assignment of the device. Since we have multiple interfaces we can be MFG, SPI and CDC all at the same time on the CY7C65215 and CY7C65215A

My proposal:

  • further refactor the code to allow the cli.py also to be more flexible and support multiple interfaces at the same time. DiscoveredDevice.curr_cy_type becomes a set of values rather than a single value.
  • In most situations it will be clear based on the desired operation which USB interface has to be used.
  • In some situations the -s parameter will be needed to distinguish which of two SBC interfaces you want to use, if you have 2x SPI and are trying to do a SPI read, for example

Furthermore:

  • we disable any kind of auto-configuration of the device type for the dual channel devices. The semantics are far too complex from my point of view, and user support will be a nightmare.
  • So instead if the type of interface isn't available for the operation you want, you get an error.
  • You can still read/write the configurations, so the user can manage type changes themselves by preparing the configs they need in advance using the GUI tool, and loading them explicitly when needed.

@multiplemonomials
Copy link

Nice work on this refactoring! I definitely agree that the current code needs a lot of work for dual channel devices. I might suggest simply having one DiscoveredDevice object map to one SCB, so you would just return two DiscoveredDevices (one with scb = 0, one with scb = 1) when you encounter a dual channel device.

@runger1101001
Copy link
Author

Sorry for the long delay. It's been busy over the Xmas season.

However, I have made some small progress, and will now try to spend a bit more time on this again.

I've made these:

image

and would like to send you one... I'll try to DM you on GitHub if that's possible to get your shipping address. It's got the CY7C65215A on there.

I'm testing the code with this board as well as my CY7C65215 EVM now.

The CY7C65215A doesn't support JTAG, but instead it support SPI with CDC support. When you configure the device to have a SPI-CDC interface, it looks exactly the same from the endpoint standpoint as when you configure a UART-CDC interface. So this needs to be investigated more closely.

The devices are very flexible. Depending on whether you have dual channel or single channel you could have up to 5 endpoints, depending on the configuration that was flashed. VID/PID and serial string is all configurable. The only constant is the MGR interface, which always seems to be the last endpoint enumerated.

Given all this, it's hard to identify the device reliably by enumerating the endpoints.

One way to solve it would be to try to call the CyGetSignature API and check the device signature. If I understand this API correctly, this would remain constant regardless of the configuration changes to endpoints made by the user, and is available on the MGR endpoint. However, this would require interacting with the USB devices, and at least on the Mac this would require sudo privileges - not really practical.

Regarding the 2 DiscoveredDevices, this is probably the right approach, I'll look into that. In terms of comms devices, it could be 0, 1 or 2, but maybe we should also consider future "quad" devices or something, and just be more flexible with it in general.
Also the SBCs - I think we should hide this complexity form the user, except in the rare cases where its needed to disambiguate what the user is doing.

@multiplemonomials
Copy link

Woah awesome! Is that like a sort of bus pirate clone using the CY7C65215? Neat board!

I actually started out using the Bus Pirate v3, but was so disgusted by how janky it was (SPI sniffing required the frequency to be known ahead of time, I2C sniffing did not work, no fully featured host libraries for communicating with it, etc) that I moved to other options.

@runger1101001
Copy link
Author

runger1101001 commented Jan 10, 2025

:-) Bus Pirate is a lot more sophisticated, with a MCU on there. This is just a basic break-out board for the CY7C65215 / CY7C65215A. The available evaluation modules from Infineon are expensive and not in a very useful shape. This breakout board makes the CY7C65215 useable in a similar way to these kind of modules which are commonly used with the FT2232H.

So you can use as a Serial to USB dongle, or to do things like talk to an I2C bus, or to program memories or MCUs via SPI, Serial or JTAG.

I actually can't figure out how to send DMs on GitHub, don't know if its supported... but I've found the email listed in your GitHub, and have sent you a message there...

@runger1101001
Copy link
Author

I've been working on this a bit more, and have a number of results and questions to share:

  1. device identification - at the moment we can either scan and find a single device, or use a device based on serial string. This seems ok in principle. finding the devices is quite complicated, as discussed above. We still need to define the way to reliably ID a device, considering all the different options.

  2. connecting to device. at the moment the code assumes a single SBC, and you only want to open one, or the MFG. But what about code that would like to open both, or neither (see below)? Shouldn't we support (during the connection and discovery phase) connecting to a device independently of the number of SBCs and MFG, and resolve these questions later when the user tries to do operations? E.g. if you try to use serial comms and there is no UART, you get an error at that point and not when you trying to connect to the device?

  3. connecting to device. at the moment the code connects either to MFG or to a SBC device. But there are many calls you can make (including setting GPIO) that can be done without opening an interface, just by sending the device control commands. This would be important to support, as I think a primary use case for the GPIO will be to set them while using the serial terminal, or I2C or SPI via some tool. So I think we need a connection mode where it doesn't insist on "grabbing" an interface.
    Note (at least on my Mac) it's also not needed to detach other kernel drivers if you just want to send CTL messages. So I've tested using Serial connection (using CoolTerm via the MacOS CDC driver) while setting GPIO via Python and libusb. This works.

  4. Auto-switching devices: this seems to be a primary function in the CLI and sbc_context. But I think it's not a good idea really. I think the switching of the device modes should be in control of the user. The device programming code doesn't understand the format of the configuration messages, and so you can't account for all the different GPIO settings and CapTouch settings the user might have configured - there would be 1000s of combinations.
    So switching types depends on the user have pre-configured some different configuration files which he can use to switch between different modes. So I would place it under explicit control, and never reprogram the device automatically.

  5. CDC-SPI: when I configure CDC-SPI, I get exactly the same kind of interface as when I configure CDC-UART. There seems to be no way to tell them apart from the USB descriptors. I wonder if this is a limitation of my MacOS, or a problem of the CY7 chip, and whether Windows/Linux have the same issue. So this would be something we need to resolve, if possible, or we'll be recognising the CDC-SPI interfaces as if they are UARTs...

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

No branches or pull requests

2 participants