STM32F7 UART5 issue
Before I explain the problem, I have to give some background. Our project went through a long stage of Proof-of-design, in which a maintenance program was written which tests all the interfaces. Part of this incuded BIT routines for those interfaces.
The project has moved to a new stage, including a bootloader and application. The bootloader incorporates much of the BIT testing from the maintenance program.
The issue is that for UART5, the BIT test works correctly in the maintenance program, but fails as part of the loader program. I have put in a couple of days debugging, and see things I cannot explain.
There are 6 UARTs in our system. 5 of them are RS422 with an external driver chip, 1 is a HW selectable RS232/422 with and external driver chip. The BIT works on all of these, except UART 5 in the loader (UART 5 is one of the standard RS422s).
The BIT works by putting the UART into loopback made, then sending and receiving (by polling) the characters ‘A’..’Z’. Here is the routine which has been working:
static bool SerialBITInternal(UART_HandleTypeDef *p)
{
uint8_t i, data = 0;
bool result = true;
UART_EndRxTransfer(p); // cancel the wait for an interrupt if there is one, we work polling here in the BIT.
for(i = 'A';i
{
HAL_UART_Transmit(p, &i, 1, 10);
HAL_UART_Receive(p, &data, 1, 10);
if (i != data)
result = false;
}
return result;
}
Surrounding the calls to the routine are routines which make the DXEN of the chip a regular GPIO and drives it low (so the loopback remains internal to the UART).
The issue with UART 5 under the loader is evident when debugging. When I arrive at the for loop in the routine, I have (in the loader only) for reasons unknown, a value of 0x006000F0. This is an overrun error. I added the code to the routine __HAL_UART_CLEAR_OREFLAG(p) after the call to UART_EndRxTransfer to fix this (in fact, added macros clearing all of the error flags). This doesn’t work when running – it does work if I place a breakpoint after them but before the test. As soon as I start the test with 0x006000D0 in the ISR, the test passes. But no matter what I do to clear the error, until I hit a breakpoint it does not change.
Note that this is only an issue for UART5 – all the other U(S)ARTs are fine.
The main difference between the maintenance program and the loader program is that the loader program runs from RAM. I tried adding a cache clear after call to __HAL_UART_CLEAR_OREFLAG, but this did nothing. Only a breakpoint. If I break before it, and step through it, like this:
bool result = true;
UART_EndRxTransfer(p); // cancel the wait for an interrupt if there is one, we work polling here in the BIT.
__HAL_UART_CLEAR_PEFLAG(p); // break here and step through
__HAL_UART_CLEAR_OREFLAG(p);
for(i = 'A';i
…
I can see the ISR register change value, and then if I run to the “return result�? everthing is OK. If I break in the middle of the “for�? loop, then I can see that (a) result is already false, (b) the value is 0x006000D0 and (c) the value in the RXD is the same as the value in the TXD. This, I believe, is caused by the breakpoint, because otherwise it would have happened sooner.
UART5 is, on my board, what we number as 1, so it was the first UART being tested. I changed the order of the testing of the UARTs, only UART 5 suffers from this problem.
To summarize: Only UART5, only when running from RAM, reason is an unknown-cause overrun error, which does not clear until a breakpoint is reached.
