STM32 USB boot conundrum - Page 1
Forum section: electronics / general

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 12:14:25 pm
content: I am designing a (hobby) project around an STM32F3. The device will have a LiPo battery, and is meant to have a "soft" power switch and the ability to go into standby on its own after a timeout, implemented simply via the STM32's Standby mode. So the regulated VDD supply voltage will always be present, to enable the processor to wake up again when the soft-power button is pressed.The device will also have a USB port, for charging the battery and for an optional data connection. This particular STM32 processor does not have an integrated 1.5k pullup on USB_DP, so I need to provide that externally. USB enumeration should occur when the STM32 is woken up, and must not be tried in vain when a sleeping STM32 is connected to the host. So I intend to connect the 1.5k pullup to a GPIO pin of the STM32 rather than to VDD, and set that pin high in my code when the STM32 wakes up.So far, so good.But now Ialsowant to use the STM32 boot loader to enable firmware updates via USB. There will be a jumper for the BOOT0 pin to select booting from flash vs. USB. Buthow do I get the 1.5k pullup to be activated when the boot loader kicks in?!Is there any GPIO pin which the boot loader or the hardware sets high? Is there another trick, e.g. some other side effect of the STM32 waking up? I would like to avoid additional hardware (external flip-flop or such) if possible.Thanks for your ideas!

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 16, 2022, 01:32:55 pm
content: You don't really need the power to be present, lots of regulators have Enable input, so just wire than pin to the button and the stm32, once the STM32 boots it should latch the pin to keep the power enabled.As far as I know, the bootloader will handle the usb automatically, including the pullup, you don't need to configure anything.Also, you can boot into the bootloader without physically modifying BOOT pins, issuing a direct call from your firmware:https://stackoverflow.com/questions/26891432/jump-to-bootloader-in-stm32-through-application-i-e-using-boot-0-and-boot-1-pinshttps://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/https://michaeltien8901.github.io/2020/05/30/Jump-to-Internal-Bootloader-STM32F4.html

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 16, 2022, 01:50:23 pm
content: Quote from: ebastler on November 16, 2022, 12:14:25 pmAN2606: STM32 microcontroller system memory boot modedescribes the boot loader (DFU, for USB).As far as I can see, a transistor with a weak resistor to enable it by default, that a GPIO pin can disable by driving it, seems like a requirement to me.Unless, of course, you switch to boot loader using a jump from your own code, as described in the abovementioned appnote.

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 02:22:33 pm
content: Thank you both!Quote from: DavidAlfa on November 16, 2022, 01:32:55 pmBut if the STM32 boots into the bootloader (rather than my own code), it won't set that pin, right?QuoteNo, as mentioned my STM32F3 does not have an internal pullup for the USB data line. Some of the STM32 series do have it, some don't.Quote from: Nominal Animal on November 16, 2022, 01:50:23 pmI had tried my luck with AN2606 and found it helpful to understand how the bootloader decides which serial interface to boot from. But did not find anything about additional outputs driven by the bootloader -- which probably means it does not do that...If I had the 1.5k pullup activated by a transistor by default -- how would I keep it disabled while the STM32 is in standby mode? I understand that all GPIOs go to high impedance state while the STM32 is on standby. And unfortunately it seems they stay like this while the bootloader is doing its thing. Hence I can't distinguish between "standby" and "booting" state, unless I add some extra logic which latches the wakup button press?Not taking the direct route to the bootloader (via BOOT0) but calling it from my own code would be an option. Not as bulletproof though, in case I upload some messed-up code. And I would still need to provide a separate SW/JTAG interface for the initial upload.Maybe I will just add another jumper for forcing the USB pullup high when the BOOT0 jumper is set?

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 16, 2022, 03:48:39 pm
content: Quote from: ebastler on November 16, 2022, 02:22:33 pmOn STM32F301C8 the DAC output (PA4) ought to be retained during standby if VDDA is available. (I could be wrong, though, so perhaps ask ST to verify?)I do suspect that some kind of MOSFET-enabled pullup with logical OR between the BOOT0 and a GPIO pin, perhaps via a dual Schottky or just resistors, is a more robust approach. Or one of those configurable logic gates like 74LVC1G58 or 74LVC1G98, with BOOT0 as one of the inputs, and the output the gate to the logic-level MOSFET for the pullup. Two SOT-23 (SOT-23-3 and a SOT-23-6) or smaller dirt-cheap chips would perhaps be acceptable?EDIT to add:At least Mouser does have flip-flops in SOT-23 and SC70-6 (TI SN74LVC1G374) in stock, so perhaps your original flip-flop solution would be more acceptable, and it was just a matter of not realizing they do come in nice tiny (but hand-solderable) packages also, not just in SOIC and such?

author: Sauli
author_rank: Contributor
timestamp: November 16, 2022, 05:52:53 pm
content: QuoteI would imagine that USART1/USART2 transmit pins are set high by the bootloader. I don't know if they stay high after the bootloader detects activity in the USB port.

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 06:18:31 pm
content: Quote from: Nominal Animal on November 16, 2022, 03:48:39 pmThat's what I was just gravitating towards. Realized that I don't need a second jumper to pull up the "hot" end of the 1.5k resistor, since the BOOT0 input conveniently gets jumpered to VDD to enable USB boot. The most primitive solution should be just a Schottky diode from BOOT0 to the resistor, since the other source driving the resistor will be a GPIO which is either high-impedance (STM32 at standby) or high (running). Or an OR gate in a small single-gate package, for a cleaner solution. I will give that a try!

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 06:21:50 pm
content: Quote from: Sauli on November 16, 2022, 05:52:53 pmNeat idea! Unfortunately AN2606 suggests that the bootloader first looks at the USB port, and looks for incoming data on the USART if no valid levels are seen on USB. But that does not exclude the possibility that the USART already gets initialized before. I will try and measure!

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 16, 2022, 07:49:02 pm
content: Yeah, AN2606 says you must connect a 1.5K pullup resistor.So, what's the problem of doing so?It clearly shows it will loop between USB and uart until the USB cable was detected or 0x7F was received in some uart.So you can use a small p-fet with 100K to gnd so it activates by default, powering the pullup, that you later disable when booting normally. In bootloader mode pins will be Hi-Z, thus the fet will turn on.Or use Tx pin output.

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 08:42:00 pm
content: Quote from: DavidAlfa on November 16, 2022, 07:49:02 pmThe problem, in my understanding, comes with my intended use of Standby mode. All GPIOs are high-Z in Standby mode, so the p-FET would be activated in this mode also. Hence when a USB connection is made, USB enumeration is attempted and fails (since the STM32 is down).I think my "dirty" solution should work: Just tie the pullup to BOOT0 and to a GPIO. After a normal start of the STM32, the GPIO will be set high; when boot from USB is selected, the BOOT0 jumper to VDD will pull the 1.5k resistor high instead.

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 16, 2022, 08:50:19 pm
content: Or tie that resistor to uart TX, couldn't be easier.Set it as input/analog mode (hi-z) so it won't trigger USB detection out of bootloader mode.But the stm32 should wake up when the USB is connected, otherwise what are you trying to do?

author: ebastler
author_rank: Super Contributor
timestamp: November 16, 2022, 09:16:05 pm
content: Quote from: DavidAlfa on November 16, 2022, 08:50:19 pmCharging the battery?

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 17, 2022, 01:14:28 am
content: Well, then I don't see the problem anywhere.The UART might get disabled when the USB is detected, but tte 1.5K resistor is only required for detection, you should have enumerated already.

author: ebastler
author_rank: Super Contributor
timestamp: November 18, 2022, 12:47:04 pm
content: Quote from: DavidAlfa on November 17, 2022, 01:14:28 amI thought that releasing the pullup signals a disconnect to the host? So D+ needs to be pulled high as long as one wants to maintain the connection?

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 18, 2022, 01:44:42 pm
content: Not 100% sure, but I think it's used purely for detection, once host detects the pullup it will wait ~100ms and start talking to the device.Can't remember exactly, but I think the USB standard specified that initialization time.

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 18, 2022, 02:32:03 pm
content: Full-speed USB 2.0 device signals disconnect by driving both D+ and D- below 0.3V (VOL). The 1.5k pull-up on D+ is only used during speed detection, but theUSB 2.0 Specificationdoes imply that the pull-up should be enabled whenever the device may receive data. (Well, Figure 7-22 in resistor_ecn.pdf says so explicitly.)What works in practice is a different thing, of course.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: November 18, 2022, 02:33:01 pm
content: The pullup must be present all the time. Removal of pullup signals disconnect (that’s how i.e. a “soft remuneration” works - remove pullup, wait, connect it back, enumerate as a different device).

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 18, 2022, 04:00:55 pm
content: At this point, I think making a table of the required states would help a lot. Something likeVUSBJumper1.5kBOOT0CommentLow Yes No NoLow No No NoHigh Yes Yes YesHigh No Yes NoDefaultHigh No No NoWhen triggered by MCU software and D+ and D- driven lowIf we assume the above is right (it probably is not), then the conclusion is that you do need some kind of external logic to handle the 1.5k pull-up on D+. It will be affected by whether USB 5V is present (because when there is no voltage there, the D+ must not be pulled up either), whether the bootloader jumper is selected or not, and even be able to be disabled via GPIO, noting that in standby mode GPIOs will revert to hi-Z. So, not just 3-input 1-output logic, but something with internal state. (An additional input, or a RESET, might also be useful.)Are you sure you need to go down to STM32 Standby? In Stop mode, STM32F301C8 retains SRAM and register contents, and VDD current consumption is down to 6 µA, compared to the 1 µA or so of the Standby mode (VDDA current is roughly the same, around 1 to 3 µA, depending).

author: ebastler
author_rank: Super Contributor
timestamp: November 18, 2022, 04:53:14 pm
content: Quote from: Nominal Animal on November 18, 2022, 04:00:55 pmGood idea. Let me try:StateVDDUSBBOOT0GPIO to PullupPullupApp running3.0V0V/5VL (via pulldown)HHBootloader3.0V5VH (via jumper)ZHSleeping3.0V0V/5VL (via pulldown)ZZCharging3.0V5VL (via pulldown)ZZUnder regular operation, a GPIO output will pull up the "hot" end of theZenerresistor. It will automatically be high-Z when the STM32 goes to standby. To bring the pullup high while the bootloader is active, I think a Schottky diode from BOOT0 input to the hot end of the resistor should do the trick? Slightly dirty, since the voltage will be below the 3.0V spec, but I trust that this will still be recognized.

author: ebastler
author_rank: Super Contributor
timestamp: December 11, 2022, 12:39:08 pm
content: A quick follow-up, after testing Rev 1 of my board: The idea of pulling up the 1.5k series resistor via either a GPIO (when my application is running), or via a Schottky diode to BOOT0 (when the bootloader is activated), works fine.I checked the UART1 and UART2 TX pins to see whether they could be an alternative for pulling up the resistor. But at least for the chip I am using (STM32F373) the bootloader does not set them to output High. They are set as inputs with a weak pullup while the bootloader waits for either the USB connection to come alive, or a magic character to be received on one of the UART RX lines.So I will stick with the Schottky diode which seems to do the job nicely. The only thing this scheme does not support is to start the application directly from the bootloader after downloading it: I can't remove the BOOT0 jumper until the code download is complete, and then the newly started application can't force a USB re-enumeration since the jumper is still pulling the USB line high. But I can live with the need for a reset or power-cycle at that point.