Search code examples
usbstm32microcontrollerkeillorawan

Why can't I integrate the CubeMX USB MSC code into the default end-node I-CUBE-LRWAN project?


I want to add USB MSC (Mass Storage Class, so USB storage drive) functionality to my Murata B-L072Z-LRWAN1 board. For this I have used the most recent I-CUBE-LRWAN end-node project and generated USB MSC code. I have done this in the past for older versions of the I-CUBE-LRWAN (a 2018 release) and gotten it working. However if I do it now I get two behaviours:

  • Flash the board, connect it and then I reset the board. Nothing happens. No flashing lights, debug serial output, no USB and no LoRaWAN.
  • Flash the board, connect it and then start a debugger session, I let it run freely without any breakpoints: full operation, lights work, debug serial works, USB presents itself and windows says it needs to format the drive. (Which is correct as the most barebones version does not have any storage interfacing added)

I can't explain this. Why does the code work when the debugger is attached but fully locks up when it is not? As for the changes between the older and newer versions of I-CUBE-LRWAN: they have changed from the systick to an RTC based timing setup. I however can't figure out how this is related to the debugger.

Removing the USB Device cable does not make the code run.

When I comment out the call to MX_USB_DEVICE_Init, windows sees an unidentifiable USB device but none of the code works (e.g. no debug UART output). When I uncomment MX_USB_DEVICE_Init nothing happens, no USB connect.

I'm using Keil uVision as my IDE. Compiler version: "default compiler version 6"

To replicate this you need a B-L072Z-LRWAN1 (modified to enable the USB pins) or that Murata chip with USB port. The full Minimal, Reproducible Example is to take the end-node project from I-CUBE-LRWAN and generating the USB MSC code in STM32CubeMX. (Target MCU is STM32L072CZTx). Then add all the USB MSC files to the end-node project and making the following additions to the project:

Add the USB_IRQHandler to stm32l0xx_it.c:

extern PCD_HandleTypeDef hpcd_USB_FS;
/**
* @brief This function handles USB event interrupt / USB wake-up interrupt through EXTI line 18.
*/
void USB_IRQHandler(void)
{
  HAL_PCD_IRQHandler(&hpcd_USB_FS);
}

Append the following clock configuration to SystemClock_Config:

RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
while(!LL_RCC_HSI48_IsReady());
    
/*USB clock initialization  */
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_USB;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
  Error_Handler();
}

And add the included #include usb_device.h and call to MX_USB_DEVICE_Init(); in the main.c


In relation to my old code, when I flash this to my board USB does work together with everything else (LEDs, LoRaWAN, debug UART).


Running the USB MSC code on it's own works. Running the LoRaWAN code on it's own works. The problem only manifests in the merger of these two.


Solution

  • The problem is that printf is being called because of the following definitions in usbd_conf.h.

    /** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
      * @brief Defines for configuration of the Usb device.
      * @{
      */
    
    /*---------- -----------*/
    #define USBD_MAX_NUM_INTERFACES     1
    /*---------- -----------*/
    #define USBD_MAX_NUM_CONFIGURATION     1
    /*---------- -----------*/
    #define USBD_MAX_STR_DESC_SIZ     512
    /*---------- -----------*/
    #define USBD_SUPPORT_USER_STRING     0
    /*---------- -----------*/
    #define USBD_DEBUG_LEVEL     3
    /*---------- -----------*/
    #define USBD_SELF_POWERED     1
    /*---------- -----------*/
    #define MSC_MEDIA_PACKET     512
    
    /****************************************/
    /* #define for FS and HS identification */
    #define DEVICE_FS       0
    
    /**
      * @}
      */
    
    /** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros
      * @brief Aliases.
      * @{
      */
    
    /* Memory management macros */
    
    /** Alias for memory allocation. */
    #define USBD_malloc         (uint32_t *)USBD_static_malloc
    
    /** Alias for memory release. */
    #define USBD_free           USBD_static_free
    
    /** Alias for memory set. */
    #define USBD_memset         /* Not used */
    
    /** Alias for memory copy. */
    #define USBD_memcpy         /* Not used */
    
    /** Alias for delay. */
    #define USBD_Delay          HAL_Delay
    
    /* DEBUG macros */
    
    #if (USBD_DEBUG_LEVEL > 0)
    #define USBD_UsrLog(...)    printf(__VA_ARGS__);\
                                printf("\n");
    #else
    #define USBD_UsrLog(...)
    #endif
    
    #if (USBD_DEBUG_LEVEL > 1)
    
    #define USBD_ErrLog(...)    printf("ERROR: ") ;\
                                printf(__VA_ARGS__);\
                                printf("\n");
    #else
    #define USBD_ErrLog(...)
    #endif
    
    #if (USBD_DEBUG_LEVEL > 2)
    #define USBD_DbgLog(...)    printf("DEBUG : ") ;\
                                printf(__VA_ARGS__);\
                                printf("\n");
    #else
    #define USBD_DbgLog(...)
    #endif
    

    So the solution for this version of the I-CUBE-LRWAN is to set the value of USBD_DEBUG_LEVEL to 0. Another option is to fix this by changing printf to APP_PRINTF.

    Another problem is that the sleep function in the sequencer leads to problems. Setting the define LOW_POWER_DISABLE to 1 in sys_conf.h disables the Stop mode.

    If more fine control is needed during USB operations then calling this line in the correct set and unset modes will make it work:

    UTIL_LPM_SetStopMode((1 << CFG_LPM_APPLI_Id), UTIL_LPM_DISABLE);
    

    (low power is handled in sys_app.c:96.