cancel
Showing results for 
Search instead for 
Did you mean: 

trouble shooting USB MSC device firmware

torsten2
Associate II
Posted on March 26, 2016 at 16:57

Hello,

I could use some help. I have to implement a USB Mass Storage device on a STM32L476. The final hardware is not ready jet, so I started by using a stm32476RG Nucleo board. I�ve started with the MSC_Standalone example, that is shipped with the STM32 Cube library version 1.4. I�ve replaced all storage callbacks with empty stubs (that currently just asserts(false)). The software builds fine under GCC and runs after initializing into the main loop without any faults or asserts. I wired an USB cable to the Nucleo (D+ to PA12, D- to PA11 and 5V to PA9; PA10, the configured ID Pin is open), no external pullup resistors are used.

The 8MHz from the stlink part of the board is connected to the HSI input (OSC_IN).

When I connect the USB cable to a PC, nothing happens. I can measure 5V at PA9, but on both D+ and D-, 0V and no signals. No I�ve checked the content of all OTG (device) registers, but found no obvious error.

Have you any suggestions for me, how to debug / trouble shoot this? Any tests that I can make to get more insight in my issue?

Thank you very much in advance and kind regards,

Torsten

#usb #msc #msc #usb #stm32l4
11 REPLIES 11
torsten2
Associate II
Posted on March 29, 2016 at 11:41

I can be sure (i've set a break point and the break point was reached), that USB_DevConnect() was called and thus the pullup/down resistors should be enabled by deleting the SDIS flag in the OTG_DCTL register. But I still see no signal on either D+ or D-.

In addition, the OTG interrupt service routine is never called. I made sure, that the interrupt vector table contains the correct value. I checked that HAL_PCD_MspInit() got called, which enables the interrupt.

What puzzles me, is that the SUB_Device/MSC_Standalone example does not call HAL_PCD_MspInit(). Maybe it was just an overlook, there seems to be not much of importance in that function.

Any idea how I can get more insight on why the pullup resistors are not active?

torsten2
Associate II
Posted on March 29, 2016 at 13:30

I've activated the internal bootloader by activating the BOOT0 pin. Now I'm very sure, that the hardware is working correctly.

I debugged the internal bootloader to see how the OTG registers are configured and I see a huge different in the GOTGCTL registers. Most bits set by the bootloader are not documented by the Reference manual (RM0351/DocID024597 Rev 3) (Value 0x030900cc). When I look up the value from the CMSIS (STM32Clube_FW_L4_V1.4.0) device header (stm32l476xx.h) most bits set in the register value make sense.

This defines

#define USB_OTG_GOTGCTL_SRQSCS                  ((uint32_t)0x00000001U)         /*!< Session request success */

#define USB_OTG_GOTGCTL_SRQ                     ((uint32_t)0x00000002U)         /*!< Session request */

#define USB_OTG_GOTGCTL_VBVALOEN                ((uint32_t)0x00000004U)         /*!< VBUS valid override enable */

#define USB_OTG_GOTGCTL_VBVALOVAL               ((uint32_t)0x00000008U)         /*!< VBUS valid override value */

#define USB_OTG_GOTGCTL_AVALOEN                 ((uint32_t)0x00000010U)         /*!< A-peripheral session valid override enable */

#define USB_OTG_GOTGCTL_AVALOVAL                ((uint32_t)0x00000020U)         /*!< A-peripheral session valid override value */

#define USB_OTG_GOTGCTL_BVALOEN                 ((uint32_t)0x00000040U)         /*!< B-peripheral session valid override enable */

#define USB_OTG_GOTGCTL_BVALOVAL                ((uint32_t)0x00000080U)         /*!< B-peripheral session valid override value  */

#define USB_OTG_GOTGCTL_BSESVLD                 ((uint32_t)0x00080000U)         /*!<  B-session valid*/

do not fit together with the documentation of the ''OTG control and status register (OTG_GOTGCTL)''

Ups, tried to upload a screenshot, but the ''Image Manager'' seems to not work with a Safari. Here is a look to the screenshot: 

http://robitzki.de/OTG.png

Why is there a difference in the documentation and in the headers? Do I have an old version of the reference manual?

Kind regards,

Torsten

torsten2
Associate II
Posted on March 29, 2016 at 13:36

I've checked that Version 3 is the current version of the document (or at least the one, that is offered to be downloaded atm).

tsuneo
Senior
Posted on March 30, 2016 at 20:56

Hi Torsten,

> When I connect the USB cable to a PC, nothing happens. Maybe, the OTG_FS isn't fed with right clock. - PLL fails to lock, because of wrong setting or wrong clock source. Using CubeMX(v4.14) and STM32Cube_FW_L4_V1.4.0, you may generate USB MSC example for NUCLEO-L476RG. The procedure is as follows, A) Code generation on CubeMX 1) run CubeMX, File menu > New Project, Board Selector tab, NUCLEO-L476RG and OK - Pinout dialog appears 2) At the left pane, - expand Peripherals - USB_OTG_FS, mode: Device Only - expand MiddleWares - USB_DEVICE, Class For FS IP: Mass Storage Class - expand Peripherals - RCC There are two options for RCC a) Low Speed Clock (LSE): Crystal/Ceramic Resonator OR b) High Speed Clock (HSE): BYPASS Clock Source As the default, NUCLEO-L476RG doesn't connect 8MHz clock (MCO) from the on-board ST-Link. - If you would leave the clock as the default, take a) option. - You may route the 8MHz clock by soldering SB16 and SB And then, take b) option. 3) Click ''Clock Configuration'' tab, and push ''Yes'' button to make the clock config sorted out automatically. 4) Project menu > Settings, fill ''Project Name'' and Project Location''. Choose Toolchanin pull down, and push OK 5) Project menu > Generate code. Now that the example is generated. If you would take a) clock option, you have to modify the source code.

main.c
/** System Clock Configuration - modified for USB_USE_LSE_MSI_CLOCK
*/
static void Error_Handler(void)
{
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/* Enable the LSE Oscilator */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Enable the CSS interrupt in case LSE signal is corrupted or not present */
HAL_RCCEx_DisableLSECSS();
/* Enable MSI Oscillator and activate PLL with MSI as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 6;
RCC_OscInitStruct.PLL.PLLN = 40;
RCC_OscInitStruct.PLL.PLLP = 7;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Enable MSI Auto-calibration through LSE */
HAL_RCCEx_EnableMSIPLLMode();
/* Select MSI output as USB clock source */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_MSI;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_RCCEx_EnableMSIPLLMode();
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

B) Hardware connection NUCLEO-L476RG doesn't mount any USB B-type connector for the OTG_FS. You have to connect this connector to these pins, PA9 - VBUS (5V) <-- required PA11 - D- PA12 - D+ GND - GND C) code customization The generated code doesn't bind any ''media'' (SD Card, etc) to the MSC. Modify each routine in usbd_storage_if.c, referring to usbd_storage.c on this example. \STM32Cube_FW_L4_V1.4.0\Projects\STM32L476G_EVAL\Applications\USB_Device\MSC_Standalone\Src Tsuneo
torsten2
Associate II
Posted on March 31, 2016 at 08:57

Hello Tsuneo,

thank you very much for looking into my issue. To tell the full truth, I’m just using the STM32Cube library sources and don’t use the IDE. But I think that shouldn’t be a problem. 

I’ve soldered the jumpers to get 8MHz from the st-link part of the board to the controller. And as the internal USB Bootloader works, I’m sure that USB cable is connected correctly to the board. But I made a quick test, opened the jumpers for the external 8MHz and checked, if the internal bootloader is still working. It is! That means that the internal bootloader is not using the external HSI source. I used your SystemClock_Config() function to initialize the clock from internal sources, but unfortunately, this doesn’t lead to the D+ line being pulled up.

So I think it’s possible, that my problem are bad initialized clocks. Can you think of any test to make sure that the clocks are correctly initialized?

Thank you very much,

Torsten

torsten2
Associate II
Posted on March 31, 2016 at 11:34

Voilà, at least one error found! The example from Cube use the STM32L476 EVAL board, which has a 8Mhz quartz, while my nucleo board has an external 8Mhz source. But still, no pullup resistor visible on the DP pin :(

I’ve checked the RCC registers and they have the following values:

Clock control register:

=======================

(gdb) x/x 0x40021000

0x40021000: 0x03070063

0x03070063 boils down to:

MSION:    1: MSI oscillator ON

MSIRDY:   1: MSI oscillator ready

MSIPLLEN: 0: MSI PLL OFF

HSION:    0: HSI16 oscillator OFF

HSEON:    1: HSE oscillator ON

HSERDY:   1: HSE oscillator ready

HSEBYP:   1: HSE crystal oscillator bypassed with external clock

PLLON:    1: PLL ON

PLLRDY:   1: PLL locked

PLL configuration register

==========================

(gdb) x/x 0x4002100c

0x4002100c: 0x03301803

0x03301803 boils down to:

PLLSRC: 11: HSE clock selected as PLL, PLLSAI1 and PLLSAI2 clock entry

PLLM:   000: PLLM = 1

PLLN:   0011000: PLLN = 24

PLLPEN: 0: PLLSAI3CLK output disable

PLLP:   0: PLLP = 7

PLLQEN: 1: PLL48M1CLK output enable

PLLQ:   01: PLLQ = 4

PLLREN: 1: PLLCLK output enable

PLLR:   01: PLLR = 4

which leads to:

  f(VCO clock) = f(PLL clock input) × (PLLN / PLLM) = 8Mhz x (24 / 1) = 192MHz

  f(PLL_Q)     = f(VCO clock) / PLLQ = 192MHz / 4 = 48Mhz

AHB2 peripheral clock enable register

=====================================

(gdb) x/x 0x4002104c

0x4002104c: 0x00001001

0x00001001 boils down to:

GPIOAEN: 1: IO port A clock enabled

OTGFSEN: 1: USB OTG full speed clock enabled

Peripherals independent clock configuration register

====================================================

(gdb) x/x 0x40021088

0x40021088: 0x08000000

CLK48SEL: 10: PLL “Q� clock (PLL48M1CLK) selected as 48 MHz clock

Does this looks reasonable?

ghodhban
Associate
Posted on June 23, 2016 at 14:47

Hello chinzei.tsuneo,

I tried to find the STM32Cube_FW_L4_V1.4.0.zip, on ST website, but I can't ?

 

please, could you send me a link to this source folder ?

I appreciate your help

Posted on June 23, 2016 at 15:04

Have CubeMX download that library, or go the the L4 Cube page and download the current version of that...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ghodhban
Associate
Posted on June 23, 2016 at 16:10

Hello clivel,

thank you, but this version don't include example for STM32L486RG 

 

 

thanks again