cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 USB DFU bootloader not working reliably

Lee3
Associate III

I have a self powered STM32F446 with 24 MHz oscillator, not crystal. When trying to activate the bootloader mode, I get variable results. Sometimes it shows up properly, sometimes it shows up but in a corrupted type of state, and sometimes it doesn't come up at all. The corrupted states seems to get most of the usb descriptors correctly, but the string descriptors don't come up as well.

I use USB in the main application mode of my program as well, and that works without issue.

A previous design with the F446 that was usb powered, 24 MHz crystal had no issues. Some of the pinout has changed between designs. Any ideas where I should be looking? Improper clock detection? Other bootloader mode activated, but still somewhat communicating over USB?

Example top of descriptor, corrupted,

Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x0483 STMicroelectronics
  idProduct          0xdf11 STM Device in DFU Mode
  bcdDevice           22.00
  iManufacturer           1 (error)
  iProduct                2 (error)
  iSerial                 3 Љ
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9

6 REPLIES 6

AN2606 would indicate the pins which the ROM is looking for activity on.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Lee3
Associate III

Then my question there is if it possible that it could potentially partially communicate over usb if it entered a different mode. If so then I'd look more into the pin states and forcing them low, etc.

Lee3
Associate III

I can connect the debugger when the bootloader is running and see that in fact it's detecting the oscillator as 23 MHz when usb doesn't work. It addition the bootloader does not set HSEBYP. So is it just that the bootloader is not compatible with oscillators, only crystals?

Lee3
Associate III

So it seems that the issue is just poor HSI accuracy such that autodetect doesn't work. My measured HSI is 16.4 MHz. This is described here: https://community.st.com/s/article/FAQ-DFU-mode-with-system-bootloader-is-not-working-while-USB-does

My workaround is to trim hsi. This won't help for a brand new board, but it does for reboot to bootloader from application code. Here is some code:

// Find the best value of hsi_trim
uint8_t calibrate_hsi(uint8_t hse_freq) {
    // hsi frequency is supposed to be 16 MHz
    // Switch to hsi for sysclk, connect hse_rtc to tim11 for counting
    RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
    RCC->CFGR &= ~(RCC_CFGR_SW | RCC_CFGR_PPRE2);      // HSI at 16MHz for sysclk, APB2 at 16MHz for TIM11
    RCC->CFGR |= (uint32_t) hse_freq << RCC_CFGR_RTCPRE_Pos; // HSE_RTC at 1 MHz
 
    TIM11->OR = 2;
    TIM11->CR1 |= TIM_CR1_CEN;
    TIM11->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1PSC; // input capture IC1, max prescaler, 8
    TIM11->CCER |= TIM_CCER_CC1E;     // enable input capture
 
    int16_t min_error = INT16_MAX;
    uint8_t min_hsi_trim = 0x10;
    for (uint32_t i=0; i<=0x1F; i++) {
      uint32_t hsi_trim = i << RCC_CR_HSITRIM_Pos;
      RCC->CR &= ~RCC_CR_HSITRIM;
      RCC->CR |= hsi_trim;
 
      uint16_t start_count = TIM11->CCR1;
      uint16_t tmp[10];
      for (int j=0; j<10; j++) {
        while(!(TIM11->SR & TIM_SR_CC1IF)); // wait for capture
        tmp[j] = TIM11->CCR1;
      } 
      // The ideal total count is 10*8*16
      uint16_t total_count = TIM11->CCR1 - start_count;
      int16_t error = 10*8*16 - (int16_t) total_count;
      if (abs(error) < abs(min_error)) {
        min_hsi_trim = i;
        min_error = error;
      }
    }
    return min_hsi_trim;
}
 
// Call bootloader, trigger is go_to_bootloader==1 on reboot + software reset
uint8_t go_to_bootloader = false;
uint32_t hsi_trim = 0x10l << RCC_CR_HSITRIM_Pos;
void reboot_to_bootloader() {
  __disable_irq();
  go_to_bootloader = true;
  hsi_trim = (uint32_t) calibrate_hsi(get_pin_config()->crystal_frequency_MHz) << RCC_CR_HSITRIM_Pos;
  NVIC_SystemReset();
}
.section .text
Reboot_Loader:
    ldr     r0, =0x40023844 /* RCC_APB2ENR */
    ldr     r1, =0x00004000 /* ENABLE SYSCFG CLOCK */
    str     R1, [R0, #0]
    ldr     r0, =0x40023800 /* RCC_CR */
    ldr     r1, =hsi_trim
    ldr     r1, [r1]
    str     r1, [r0]
    ldr     R0, =0x40013800 /* SYSCFG_MEMRMP */
    ldr     R1, =0x00000001 /* MAP ROM AT ZERO */
    str     R1, [R0, #0]
    ldr     R0, =0x1FFF0000 /* ROM BASE */
    ldr     SP,[R0, #0]     /* SP @ +0 */
    ldr     R0,[R0, #4]     /* PC @ +4 */
    bx      R0

Thanks for details

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

try calibrating the HSI generator