2025-07-18 1:52 PM
I'm using UART7 on a STM32H743 to drive a RS-485 transceiver. I've set it up to use the hardware DE pin to switch the transceiver between TX and RX modes. I transmit 14byte messages to devices on the bus, and they send back ~14byte messages. My code does this TX/RX16 times a second in bursts of 8 transfers. All works well 99.999% of the time. However, at a random interval from hours down to every consecutive data transfer, I receive back junk data. It averages around 5 minutes between errors.
I put a scope on the transceiver and found that the errors are caused by the DE pin staying asserted too long after the last stop bit of a transmission ends; the transceiver stays in TX mode and blocks the incoming reception. This happens very rarely, but remains to be a headache for my system. The length of the deassertion time seems deterministic and very fast normally, but during these glitches it can be between 50 and 200us (50us is about how long it takes for the RS-485 device to respond to the transmitted package). Typically DE will overlap with a few bits of the incoming transmission, but occasionally I've seen it block a whole byte.
Originally, the assert and deassert times were set to 0 in the configuration. I tried changing these to 2 for both to see if that made a difference. It increased the normal deassert time by an appropriate amount, but the sporadic glitches continue.
Perhaps unrelated, I had an issue with the RMII bus when communicating with an Ethernet PHY chip where the timing between the TXD0/D1 and TX_EN signals did not allow enough setup time compared each other and to the reference 50MHz clock signal on the bus. Digging into it, I found that the GPIO pin speed settings needed to be set to HIGH_SPEED for the different pins' timings to be synchronized with each other and the reference clock.
I also played around with the UART pin speeds to see if there was some internal timing issue that might fix this DE pin problem; however, the problem remains at both LOW_SPEED and HIGH_SPEED settings.
Finally, I will add that we have hundreds of these boards in the field and this problem shows up pretty consistently in most if not all of them. We have firmware running the HAL libraries from 2019 (1.9, I think) as well as a newer version of firmware using the latest HAL libraries (1.12). The silicon in the devices range from purchased in 2019 to about a year ago. There's nothing in the errata about a problem like this.
My code uses HAL_UART_TrasmitIT() and HAL_UART_RecieveIT() for transfers.
Here is my setup code for the UART:
void MX_UART7_Init(void)
{
/* USER CODE BEGIN UART7_Init 0 */
/* USER CODE END UART7_Init 0 */
/* USER CODE BEGIN UART7_Init 1 */
/* USER CODE END UART7_Init 1 */
huart7.Instance = UART7;
huart7.Init.BaudRate = 57600;
huart7.Init.WordLength = UART_WORDLENGTH_8B;
huart7.Init.StopBits = UART_STOPBITS_1;
huart7.Init.Parity = UART_PARITY_NONE;
huart7.Init.Mode = UART_MODE_TX_RX;
huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart7.Init.OverSampling = UART_OVERSAMPLING_16;
huart7.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart7.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart7.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
//Our production code has the assert and deassert times at 0:
if (HAL_RS485Ex_Init(&huart7, UART_DE_POLARITY_HIGH, 2, 2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart7, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart7, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart7) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN UART7_Init 2 */
/* USER CODE END UART7_Init 2 */
}
And here is the snippet that in the MSP_init for the pins:
else if(huart->Instance==UART7)
{
/* USER CODE BEGIN UART7_MspInit 0 */
/* USER CODE END UART7_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART7;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_UART7_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/**UART7 GPIO Configuration
PE7 ------> UART7_RX
PE8 ------> UART7_TX
PE9 ------> UART7_DE
*/
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //Production code has speed at LOW
GPIO_InitStruct.Alternate = GPIO_AF7_UART7;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* UART7 interrupt Init */
HAL_NVIC_SetPriority(UART7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(UART7_IRQn);
/* USER CODE BEGIN UART7_MspInit 1 */
/* USER CODE END UART7_MspInit 1 */
}
For reference, the system clock is 480MHz and the PBCLK1 to the UART is 120MHz.
Normally, my code handles these errors by trying the transfer again up to three times. Usually this works, but very occasionally (once a month out of hundreds of systems) the retries fail and this can crash the system.
Any ideas or help would be appreciated.