2024-12-04 04:52 PM
Hello everyone, I encountered a problem while using STM32L431 for RS485 development. I used the ISO7041 isolation chip, and in the initial state, the DE pin is low, while both TX and RX are high. The current issue is that when I turn on the power, reset, and plug in 485, both the transmission and reception of 485 are normal. However, when I unplugged and inserted 485 again, an FE error occurred. Why is this? Is it because the voltage level does not match after inserting 485?
Debugging found errorsflags=2, which should be FE errors。
Here is some of my code:
int main()
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_LPUART1_UART_Init();
HAL_GPIO_WritePin(DE485_GPIO_Port, DE485_Pin, GPIO_PIN_RESET);
initSqQueue(&uart[_LPCOM].Rx, lpuartRxBuff, sizeof(lpuartRxBuff));
initSqQueue(&uart[_LPCOM].Tx, lpuartTxBuff, sizeof(lpuartTxBuff));
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_RXNE);
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE);
while(1)
{
Process_Modbus_Receive(_LPCOM); // MODBUS
}
}
void USER_LPUART1_IRQHandler(void)
{
uint8_t lpuart1_data;
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)
{
lpuart1_data = (uint8_t)hlpuart1.Instance->RDR & (uint8_t)0x00fff;
wrEleQueue(&uart[_LPCOM].Rx, lpuart1_data);
uart[_LPCOM].active = true;
}
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE) != RESET)
{
uart[_LPCOM].rxIdle = true;
__HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
}
else
{
uart[_LPCOM].rxIdle = false;
}
}
void LPUART1_IRQHandler(void)
{
USER_LPUART1_IRQHandler();
HAL_UART_IRQHandler(&hlpuart1);
}
My current solution is to modify the HAL library generated by CUBEMX, directly delete the judgment of CR3 EIE value and clear the flag bit. Is this correct? Will it affect the transmission and reception of other serial ports, or can this flag be detected elsewhere and cleared elsewhere.
// if (((isrflags & USART_ISR_FE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
if (((isrflags & USART_ISR_FE) != 0U) )
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
Solved! Go to Solution.
2024-12-05 04:39 PM
Hi, can I modify it like this?
void USER_LPUART1_IRQHandler(void)
{
uint8_t lpuart1_data;
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)
{
lpuart1_data = (uint8_t)hlpuart1.Instance->RDR & (uint8_t)0x00fff;
wrEleQueue(&uart[_LPCOM].Rx, lpuart1_data);
uart[_LPCOM].active = true;
uart[_LPCOM].holdTmr = CONST_RS_485_HOLD_TMR;
}
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_FE))//Determine whether the FE flag is set
{
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_FEF);//Clear the FE flag
openLpUart1();
initSqQueue(&uart[_LPCOM].Rx, lpuartRxBuff, sizeof(lpuartRxBuff)); // Initialize the serial port receiving buffer
memset(lpuartRxBuff, 0, sizeof(lpuartRxBuff));
}
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE) != RESET)
{
uart[_LPCOM].rxIdle = true;
__HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
}
else
{
uart[_LPCOM].rxIdle = false;
}
}
void LPUART1_IRQHandler(void)
{
USER_LPUART1_IRQHandler();
HAL_UART_IRQHandler(&hlpuart1);
}
2024-12-04 07:20 PM
After a brief look, I suppose you may do:
detect unplug of RS485, reset/re-init RS485 interface, then RS485 can work as if it is the same as power on of the board.
2024-12-04 07:22 PM - edited 2024-12-04 07:23 PM
Hi, how can I check if RS485 is unplugged? There are no other pins except for DE, RX, TX
2024-12-04 07:32 PM
perhaps from low level, it is difficult to know if unplug state, you may define - from high level - protocol level that some traffic (heart break) exist timely (such as each second). so, unplug may be detected after unplug for ~1 second.
2024-12-04 07:36 PM
What does that mean? I don't quite understand
2024-12-04 09:39 PM
Sorry, in fact I mean "heartbeat".
your may search with "communication heartbeat"
reference: What is a heartbeat in computing?
2024-12-05 03:55 AM - edited 2024-12-05 04:31 AM
@AlfRomeo wrote:when I unplugged and inserted 485 again, an FE error occurred. Why is this?
Because you get a glitch on the unplugging and/or re-plugging.
This is perfectly normal, and to be expected.
PS:
or the unplugging and/or re-plugging occurs during a frame
2024-12-05 06:25 AM
if you get frame error, reset the uart errors and start afresh, it should be ok. RS485 is not auto recovery , you have to have routines to detect errors and take action.
2024-12-05 04:39 PM
Hi, can I modify it like this?
void USER_LPUART1_IRQHandler(void)
{
uint8_t lpuart1_data;
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)
{
lpuart1_data = (uint8_t)hlpuart1.Instance->RDR & (uint8_t)0x00fff;
wrEleQueue(&uart[_LPCOM].Rx, lpuart1_data);
uart[_LPCOM].active = true;
uart[_LPCOM].holdTmr = CONST_RS_485_HOLD_TMR;
}
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_FE))//Determine whether the FE flag is set
{
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_FEF);//Clear the FE flag
openLpUart1();
initSqQueue(&uart[_LPCOM].Rx, lpuartRxBuff, sizeof(lpuartRxBuff)); // Initialize the serial port receiving buffer
memset(lpuartRxBuff, 0, sizeof(lpuartRxBuff));
}
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE) != RESET)
{
uart[_LPCOM].rxIdle = true;
__HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
}
else
{
uart[_LPCOM].rxIdle = false;
}
}
void LPUART1_IRQHandler(void)
{
USER_LPUART1_IRQHandler();
HAL_UART_IRQHandler(&hlpuart1);
}
2024-12-11 07:02 PM
In addition to the above, probably you have to have some routine at higher level to detect the break and re-start the query/reception based on your state machine. Normally we implement one master multiple slaves, so it should be easy.