Custom STM32 board and USB re-enumeration issue

Lately I've been extensively using STMs USB Virtual Communications Port (VCP) - a serial port implementation over USB. It works reasonably well with the Discovery board I used for prototyping. But not so much with my custom board.

Being a newbie in USB communications, both soft- and hardware-wise, I tried to be cautious and add EMI protection IC on USB Data Plus (DP) and Data Minus(DM) lines. I used NUF2221as the isolation device. For full-speed (FS) mode, you have to connect it in such a way, that DP gets pulled up. ID pin can be left floating for B-type devices.

Board was designed and arrived from glorious People's Republic of China. I assembled the board, together with all the necessary bypass caps, crystals, convenience buttons for resetting/bootmodes and the USB connector with the aforementioned filter.

Flashing worked, the device even enumerated on PC and appeared as a serial port. But the PC woldn't be able to connect. "Internal error". Every now and then I would succeed in connecting and actually receiving the data, but these successes would be quite sporadic.

A couple of days I spent trying to understand, what's the issue. The problem was that I did not see the pattern in times, when it would or wouldn't work. Until I realized, that it works only when you plug in USB while the board is powered or freshly reset (either by re-flashing or hardware reset). Otherwise the code wouldn't go into USB enumeration code.

As it turns out, it's an issue with USB enumeration sequence, which goes more or less as follows:
  1. Plug in
  2. PC checks for changes on the Bus
  3. PC requests info on device capabilities, if a new device is found
  4. Peripheral returns descriptor
  5. PC assigns bus address to the peripheral and loads the driver
  6. Actual communications
What was happening on my board, was that EMI protection IC would keep the DP pin pulled up even through the reset, so that PC would not see any changes on the bus. It was still expecting the device with the assigned address to be on the other end. While the peripheral itself lost the address assigned due to it being stored in the RAM during the reset. And RAM gets cleared. So the device wouldn't respond to calls on USB bus to the old address. Because it's unaware of being initialized.

So, simplest but most laborious way of working around it is either re-plugging the device after reset or re-enabling it on the PC driver side ("Have you tried turning it off and on again?")

Another workaround could be software re-enumeration request from the MCU. PC would then assign new USB address, while keeping the old stale COM port driver loaded. This eventually might pollute the driver manager, but might be acceptable for development purposes.

Actual fix would be to connect EMI filter power supply to the MCU reset line in such a way, that pulling reset low (STM32 reset line is active-low) would also shut down the filter, thus disconnecting the DP pin pullup. A simple transistor might work just fine. Issues shouldn't arise from hotwiring these 2 pins over the MCU, even if USB pins are on the diagonally opposite side of the chip from reset pin, because it's active-low, meaning, it's pulled up anyway.

No comments:

Post a Comment