2017-05-18 04:48 PM
I have a custom board that uses an STM32F415RGT6. It has USB_OTG_FS_DP on pin 45 (PA12), USB_OTG_FS_DM on pin 44 (PA11), USART1_RX on pin 42 (PA10), USART1_TX on pin 43 (PA9), plus lots of other connections.
I created a project using STM32CubeMX (whatever the release before 4.21.0 was), and 'Firmware Package for Family STM32F4' v1.15.0.
Plugging the USB connection into a host works fine; the device enumerates and I can open the virtual com port from a terminal emulator and my board can receive and send data over the USB. So far so good.
My board has a data acquisition chip connected to USART1 that starts sending data to the STM32 when it comes out of reset. The data is received, my firmware on the STM32 handles it and sends data to the host over the USB connection. Still good, this is working as expected.
The problem is that when my software/firmware on the STM32 sends data to the on-board data acquisition device, PA12 (USB_OTG_FS_DP), which is carrying on the USB connection, is pulled to ground, causing the USB connection to reset. I tried this on 3 copies of the board, same thing each time. In order to rule out some sort of a short or other oddment on the card, my hardware tech lifted the USART1_TX leg so that it isn't connected to anything on the board, and we still see PA12 go low when the software tries to send data on USART1.
Here is the init code extracted from the STM32CubeMX generated 'usart.c' for initializing USART1:
/* USART1 init function */ void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }
Here is the code from 'HAL_UART_MspInit()' in the same file that deals with USART1:
else if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = USART1_RX_Pin|USART1_TX_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Peripheral DMA init*/ hdma_usart1_rx.Instance = DMA2_Stream2; hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx); hdma_usart1_tx.Instance = DMA2_Stream7; hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4; hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode = DMA_NORMAL; hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx); /* Peripheral interrupt init */ HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ }
I have not edited this particular code since it was generated by STM32CubeMX, and I see nothing wrong with it so far as how it configures the GPIOs.
I am surprised by the behavior I'm seeing, and have not seen anyone else complaining about this, so it must be something with this configuration that causes this undesired behavior. I remain at a loss to explain it, and have not figured out how to work around it other than to add an external USB to serial chip and connect USART3 to that for the host data connection. I don't like that solution, but for the prototype, that's what we've done.
Any suggestions for a solution are appreciated.
‌ #stm32f4-usart #usb_otg_fs2017-05-19 01:38 AM
when my software/firmware on the STM32 sends data to the on-board data acquisition device, PA12 (USB_OTG_FS_DP), which is carrying on the USB connection, is pulled to ground, causing the USB connection to reset.
Read out the relevant GPIO registers' content at that moment.
JW
2017-05-20 07:35 AM
Thanks for the suggestion; I'd not thought of reading the GPIO registers. Do the HAL USART drivers mess with the pin configuration when initiating/completing transfers?
I'm on loan to another project in another building, so it will be a few days before I am back in my office, and will try to do that when I am. I'm not sure it will tell me much unless I'm lucky -- the USB connection comes back up immediately after the output is complete. I'll send a large buffer, followed by sampling the GPIO registers that control the pins in question in a tight loop until the end of transmission. I'll post the results of the test when I have them.
I wish I had a nucleo board with the stm32f415rgt on it, but I don't think they make one with that part.
2017-08-11 01:47 PM
I had a very similar problem on the STM32F411. Using USART1 TX on PA9, whenever I transmitted data it would reset the USB. I could also manually short PA9 to ground and watch it cause USB-DP to go low. I fixed this by disabling the VBUS sensing:
hpcd_USB_OTG_FS.
Init.
vbus_sensing_enable=
DISABLE;