STM32 USB SOF detection - Page 1
Forum section: electronics / general

author: Halide
author_rank: Contributor
timestamp: October 16, 2023, 03:10:29 pm
content: Hello everyone,I'm encountering an issue with USB Start of Frame (SOF) detection on my Nucleo board. My goal is to determine whether the device connected to the Nucleo's USB port is a charger or a PC. I found in the reference manual that I can read the SOF bit for this purpose. It works as expected when I connect the Nucleo to a PC – the SOF bit is set. However, when I connect it to a charger, nothing happens.The core of my requirement is to establish communication without any action from PC's side (I mean without windows USB plugging voice). My problem is that the host cuts off the VBUS line. I tried setting the SDIS bit (software disconnect bit) before using the HAL deinit function, but it didn't make any difference.Perhaps some of you have encountered a similar issue and found a solution. I strongly believe that the problem lies on the host side, as when I connect the Nucleo via a USB hub, everything works fine. Using a USB hub is not a viable solution for me; I want to understand why the host is cutting off the VBUS line. Could this be related to some form of device hard reset?If anything is unclear in my explanation, please let me know, and I will provide more details.

author: ataradov
author_rank: Super Contributor
timestamp: October 16, 2023, 05:08:40 pm
content: What do you mean by "establish communication without any action from PC's side"? USB communication requires both sides to participate.What do you mean by "when I connect it to a charger, nothing happens". Was not this the goal?Why do you need to know what is connected to the port?

author: wek
author_rank: Frequent Contributor
timestamp: October 16, 2023, 05:36:06 pm
content: Quote from: Halide on October 16, 2023, 03:10:29 pmOf course: SOF is sent out by host (usually PC) as part of the communication protocol; charger does perform the USB communication.Quote from: Halide on October 16, 2023, 03:10:29 pmI don't understand how is it related to the first part of your post, with SOF.There is no such thing as "communication without any action from PC's side". USB is a polled bus, the host (PC) polls the devices, otherwise there's no communication.Quote from: Halide on October 16, 2023, 03:10:29 pmSorry, but to me, almost nothing is clear in your explanation.JW

author: Halide
author_rank: Contributor
timestamp: October 17, 2023, 08:50:41 am
content: Hello everyone,I will try to clarify your questions.What do you mean by "establish communication without any action from PC's side"? USB communication requires both sides to participate.I need to clarify that I aim to pause communication before I hear the "connection" sound on the PC side. I have a rather intricate memory management system in place (I want to enable the MSD class), and in order to gain access to memory, I must reboot the device.What do you mean by "when I connect it to a charger, nothing happens". Was not this the goal?When I connect a charger, the SOF bit is not set, and this behavior is as expected.Why do you need to know what is connected to the port?As I mentioned, I'm unable to access the memory when the device is in running mode. Information regarding the type of connection (PC or charger) is of significant importance to me. I aim to avoid resetting the device when it's connected to a charger.I don't understand how is it related to the first part of your post, with SOF.There is no such thing as "communication without any action from PC's side". USB is a polled bus, the host (PC) polls the devices, otherwise there's no communication.I understood that some packages need to be pulled between host and device. In the sentence, "communication without any action from PC's side" I want to say that I aim to pause communication before I hear the "connection" sound on the PC side. And this is reason why I'm trying to say host that i need to software disconnect my device without unplugging cable. This approach is partially successful because I don't hear the "connection" sound on the PC side. However, after a few seconds, the host disconnects the VBUS line for a brief period and then reconnects it. I have included an oscillogram to illustrate the situation, and it's important to note that I do not physically disconnect the USB cable from the PC.

author: janoc
author_rank: Super Contributor
timestamp: October 17, 2023, 12:06:05 pm
content: Quote from: Halide on October 17, 2023, 08:50:41 amI suspect this is an XY problem.If you don't want the PC to detect your device (and try to restart it when the enumeration fails), why don't you simply disable the USB pull-up resistor? Most STM32s have it built-in and controlled by software. When that resistor is disabled, the host will not be able to detect that anything has been connected and no communication (and neither port reset by the host) will happen. That's the canonical way to implement USB device connection/disconnection without power cycling.If you mess with the SOF packet that means you are effectively telling the host - "Hello, I am here and I am ready to enumerate!" by pulling the D+ or D- line up - and then you fail to do so within the timeout window. So now the host assumes there is a problem and will try to force a bus reset (by pulling D+ & D- down), even going as far as cycling the Vbus in some cases attempting to recover communication.If you really need to detect a charger for whatever reason then the way to do so is to check whether the D+/D- pins are shorted together. If they are you have a charger (but possibly not every charger shorts them).Checking SOF is not going to be reliable because if you don't get it, you can't know whether that's because the upstream is a charger, the host is slow to react or there is whatever other software problem. You may still be connected to a computer that will ask you to enumerate later, after you have checked your SOF bit. And then what?

author: ataradov
author_rank: Super Contributor
timestamp: October 17, 2023, 05:43:58 pm
content: I don't think there is an easy way to do what you want to do. No idea when Windows connection sound happens, but it is likely that attempting to start and interrupt the enumeration process will result in a host attempting to power cycle the port.One way of doing this would be to configure the D+/D- pins as GPIO inputs with internal pull-up resistor. Then sample the value of the pins. A USB host would have 15 kOhm pull-down resistors, and embedded pull-up would be ~40 kOhm. With this voltage on the pin when a host is connected would be ~0.9 V. This is on the edge of V_IL, so GPIO detection will not be reliable and you may need to use ADC for this.Or use external switchable pull-up resistor of a much higher value (100 kOhm).

author: langwadt
author_rank: Super Contributor
timestamp: October 17, 2023, 07:54:40 pm
content: how does devices like cypress FX2 do it?it plugs, gets firmware over USB, boots that firmware and reenumerate as that device

author: ataradov
author_rank: Super Contributor
timestamp: October 17, 2023, 08:13:58 pm
content: It still fully enumerates as a blank FX2LP device. This would cause OS notification if they are enabled.

author: Halide
author_rank: Contributor
timestamp: October 17, 2023, 08:52:49 pm
content: If you don't want the PC to detect your device (and try to restart it when the enumeration fails), why don't you simply disable the USB pull-up resistor? Most STM32s have it built-in and controlled by software. When that resistor is disabled, the host will not be able to detect that anything has been connected and no communication (and neither port reset by the host) will happen. That's the canonical way to implement USB device connection/disconnection without power cycling.But if I understood that part correctly I can't detect that is the host from device side too?If you really need to detect a charger for whatever reason then the way to do so is to check whether the D+/D- pins are shorted together. If they are you have a charger (but possibly not every charger shorts them).This is the reason why I want to attempt initiating some communication. Any charger does not initiate communication on the data lines (I hope so)Checking SOF is not going to be reliable because if you don't get it, you can't know whether that's because the upstream is a charger, the host is slow to react or there is whatever other software problem. You may still be connected to a computer that will ask you to enumerate later, after you have checked your SOF bit. And then what?I'm utilizing an RTOS, which allows me to employ a dedicated thread for monitoring the SOF status. This means that until the PC initiates communication, the device can behave as if it were connected to a charger.No idea when Windows connection sound happens, but it is likely that attempting to start and interrupt the enumeration process will result in a host attempting to power cycle the port.I have an idea: I'll try using the ENUMDNE bit. This bit is set after the enumeration process, so I can end transmission after that point. If this doesn't resolve my issue, I might have to rethink my approach.However, do any of you have an idea as to why some ports allow me to halt communication? I mean, I'm using the same PC with two different USB ports. On one of them, everything works perfectly, but when I attempt to use the other, I observe a VBUS reset.Thank you all for your help so far.

author: ataradov
author_rank: Super Contributor
timestamp: October 17, 2023, 09:06:08 pm
content: It is possible that some of the port are connected to the root hub and others to some internal secondary hub. Or they connected to different host controllers and drivers for those controllers behave differently. It is impossible to say for sure.The whole thing is very strange.Improving on the idea I described earlier, an easy way to detect host would be to connect 100-200 kOhm resistor to D+ and any other GPIO. When detecting the host, set D+ as input and the other GPIO as output high. If there is no host, then D+ would be pulled high. If there is a host, D+ would be low, so you can reset into the USB mode.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: October 17, 2023, 11:27:59 pm
content: There are chargers (i.e. Apple’s Type A ones, some other brands) with various resistive dividers on D+/D- indicating charger type. Those could sabotage GPIO+pullup approach.Just for curiosity, why connection sound is a problem in the first place?

author: janoc
author_rank: Super Contributor
timestamp: October 18, 2023, 07:41:36 pm
content: Quote from: Halide on October 17, 2023, 08:52:49 pmYou might be able to detect that you are connected to a real, talking, host and not a charger - but by the time you do so it is too late because the host has already started the enumeration process. And if your device doesn't enumerate properly at that stage by sending proper descriptors, etc., it will make the host to try to reset the port, power cycle your device and ultimately report an error to the user.You can't do anything about that from the device side. Full stop.It is as simple as that. The moment you have put that pull-up resistor on the bus you are committed because USB is entirely host-driven. The only way to stop the communication is by disconnecting from the bus, which will likely cause an error message to be shown to the user.So if your goal is to prevent the host from power cycling your device at an inopportune moment because you weren't ready to communicate yet, you can't do it by trying to detect when the enumeration starts - at that point the clock is ticking already and it is too late.Quote from: Halide on October 17, 2023, 08:52:49 pmThat's completely irrelevant because if your device does not enumerate within few hundred ms or so of putting that resistor on the bus (and receiving SOF means the host has detected that already), it will get a bus reset and possibly power cycle,no matter what you do on the device side with your RTOS and threads.If you don't want to talk to the host, don't put those pull-up resistors on the bus.The proper way to achieve what you want would be to leave the USB interface off, try to check whether the two data pins are shorted, e.g. checking whether driving one with a small voltage (do not put 3.3V on the pin/drive it high - that will start the enumeration, the same as connecting a pull-up!) drives the other pin up too. If it does, they are likely shorted and you have a charger. If it does not, assume a host, do whatever you need to do andonly when you are ready to communicateinitialize the USB peripheral and connect the pull-up resistor to the bus.The host side has 15k pull-down resistors on the D+/D- lines, so they are normally idling low when there is nothing connected. Chargers short the data lines together and leave them floating.The other way to solve this is to always enumerate as some dummy device when you are connected. When that happens, you know you are talking to a host, so you do your housekeeping, disconnect from the bus by disconnecting the pull-up to force re-enumeration, then reconnect the resistor to the bus to signal new device connected. Finally reply to the new enumeration request as the real device you want to be seen as. This is very common with devices that have bootloaders for firmware update, for example like that Cypress FX2. The disadvantage of this is that you will often get two "device connected" sounds from the computer and it may confuse some users if they see some weird device connecting, then disconnecting and a new device connecting.Those two ways are the only methods to achieve what you want reliably. Messing with the SOF and trying to beat the USB host by reconfiguring your code while it is waiting for your enumeration response is bound to be fragile and unreliable.Quote from: Halide on October 17, 2023, 08:52:49 pmThat completely depends on the host, the capabilities of the hubs you are connected to, etc. Some are capable of power cycling the ports, some are not. Also the driver may be more or less "aggresive" at trying to recover the communication - some drivers/hosts could be content with just forcing a bus reset (driving both data lines low) to force a re-enumeration. Some others may also try to power cycle the port as a last resort. Either way, that's not a behavior you can rely on.

author: janoc
author_rank: Super Contributor
timestamp: October 18, 2023, 07:52:58 pm
content: Quote from: ataradov on October 17, 2023, 05:43:58 pmAFAIK once the device is enumerated the OS will at some point (possibly even many seconds later) send the notification to the user. I don't recall whether it does it only for devices it knows (and has driver for) or for any device, I haven't used Windows in a while.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 18, 2023, 08:41:41 pm
content: Quote from: langwadt on October 17, 2023, 07:54:40 pmIt first enumerates with a given VID/PID (Cypress defaults, or read from an attached EEPROM), which will trigger the host to load the corresponding driver - this first driver will upload the firmware to the FX2 RAM.Then the firmware is responsible for triggering a re-enumeration (internally the FX2 just disconnects the USB data lines for a short while and re-connects them). After that, the firmware handles USB communication, usually exposing another PID.

author: Halide
author_rank: Contributor
timestamp: November 15, 2023, 11:26:59 am
content: Hello everyone!As you said there is no possibility to keep my solution.I enable CDC class to check that there is some communication and leave it enable all the time.Thank you!Best regardsBartosz

author: peter-h
author_rank: Super Contributor
timestamp: November 16, 2023, 12:06:31 pm
content: QuoteIs that really so? There is a protocol for charging from USB - check the DS for a TPS2511 for one chip which implements this. Definitely not a simple short.QuoteExactly, and not just Apple. The whole industry uses this. I spent a lot of time in this area a few years ago. Also consider current drawn; if >90mA (IIRC) then you cannot just draw it from the +5V pin; you have to "negotiate" like the TPS2511 does. With that you can go up to 500mA (900mA on USB3, IIRC). Above that it gets more involved.I was digging around this recentlyhttps://www.eevblog.com/forum/microcontrollers/defective-usb-host-hanging-up-your-target/msg4679803/#msg4679803to see if a USB client can detect whether there is a VCP application running on the host capable of "consuming" data sent to the host, and it appears this is not possible.

author: Siwastaja
author_rank: Super Contributor
timestamp: November 16, 2023, 01:20:31 pm
content: Quote from: peter-h on November 16, 2023, 12:06:31 pmLiterally the first thing mentioned on TPS2511 datasheet:Quote

author: peter-h
author_rank: Super Contributor
timestamp: November 16, 2023, 03:04:33 pm
content: And the rest of it?I don't understand.

author: Siwastaja
author_rank: Super Contributor
timestamp: November 16, 2023, 03:09:37 pm
content: In other words, there are a few different ways of indicating "this is a charger, you can pull more than 100mA and you don't have to enumerate" - one of which, a really popular one, is shorting the data lines together. The chip you referred to implements, among others, that one.

author: nctnico
author_rank: Super Contributor
timestamp: November 16, 2023, 10:49:04 pm
content: Quote from: peter-h on November 16, 2023, 12:06:31 pmIt is. Chargers must be made cheap. The maximum resistance of that 'short' is 500 Ohm BTW. So you can implement this with crappy CMOS switches and still get away with it.

author: nctnico
author_rank: Super Contributor
timestamp: November 16, 2023, 10:52:36 pm
content: Quote from: ataradov on October 17, 2023, 05:43:58 pmIn my experience this doesn't happen as power cycling the port only adds complexity to the driver and hardware making the solution less reliable. One of the standard things I have in my USB devices is to cycle the pull-up resistor on the D+ (IIRC otherwise it is D-; just check the specs) to restart the USB negotiation. This helps to make sure the device always ends up in a state where it can communicate with the host.