1
\$\begingroup\$

I am having trouble using the UART on the STM32F103 where it stops receiving data, while not setting any of the error flags.

The UART device is an ESP8266 at 115,200 baud. I am sending it AT\r\n. The ESP8266 echoes back each byte I send -- I am able to receive these echoes. However, when it comes to reading the response after the echos (OK + some newlines), it times out after receiving one byte.

Here is the entire transaction, as seen on a logic analyzer.

logic analyzer traces

STM32 sends: A T \r \n
ESP8266 sends: A T \r \r \n \r \n O K \r \n

In my code, I send one byte, then receive one byte until the payload is sent. Then, I'm attempting to listen for the remaining 7 bytes (\n \r \n O K \r \n) one-by-one. I receive the \n, then the communication times out after 5 seconds (using the debugger, I see it's waiting on the RXNE flag.)

When the timeout occurs, I see that none of the error flags (ORE NE FE PE) are set in the SR register.

If I attempt to read two bits at a time, the very first HAL_UART_Receive call times out.

The program creates some debugging info (below) as it sends each byte and received the echo, then attempts to receive the response. The code for the program is in a gist.

I've been banging my head against this for several hours. What could cause this behaviour?

Sending 4 bytes: AT(\r\n)
  Echo:
    Byte 0: sent 65, echo 65 (ORE 0) // A
    Byte 1: sent 84, echo 84 (ORE 0) // T
    Byte 2: sent 13, echo 13 (ORE 0) // \r
    Byte 3: sent 10, echo 13 (ORE 0) // \n, echo \r
  Receive:
    Recv 10  // \n
    Recv fail
    RXNE: 0 ORE: 0 NE: 0 FE: 0 PE: 0

Excerpt of code that attempts to read the bytes after the sending completes (full code):

while (1) {
    uint8_t recvChar;
    if (HAL_UART_Receive(&Device_UART_Handle, &recvChar, 1, 5000) != HAL_OK) {
        printf("    Recv fail\r\n");
        printf("    RXNE: %d ORE: %d NE: %d FE: %d PE: %d\r\n",
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_RXNE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_ORE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_NE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_FE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_PE));
        while(1) {}
    }
    printf("    Recv %d\r\n", recvChar);
}
\$\endgroup\$
  • \$\begingroup\$ What happens if you take the logging out? Are you in control of the ESP8266 code? If so, can you 'throttle' it? Perhaps implement an acknowledge on each received byte to make it robust while using debug statements. This looks like a classic "Heisenberg effect". \$\endgroup\$ – gbulmer Jun 9 '16 at 0:09
  • \$\begingroup\$ so if you get rid of all your printf debug stuff, and say you put a few second timer (or just count to a large number even better) and buffer up whatever comes back. then after the timeout, THEN dump the count and whatever text. you still only get one character? \$\endgroup\$ – old_timer Jun 9 '16 at 0:28
  • \$\begingroup\$ ahh, I think ST is the company I pulled my hair out with. look for an OVRDIS overrun disable bit. disable that on init. you say you are not getting an ORE though. anyway, I fought that, I dont use a HAL from them so dont know how to help you there, the uart is somewhat trivial to initalize without the hal, that is how I do it... \$\endgroup\$ – old_timer Jun 9 '16 at 0:31
3
\$\begingroup\$

Chances are you are missing most of the reply because the extensive logging in your receive loop takes so long that it can't catch the next character. Even if whatever you are sending printf() output to is an order of magnitude faster than the 115200 baud response from the ESP8266, you are generating so many characters of output for each one received that it's most probable you cannot keep up.

During the initial stage when only one response character was being generated for each character sent, you could perhaps get away with it, but once the ESP8266 is free to keep a 115200 baud channel full, you have to be able to keep up with that.

Console output is indeed useful, but you have to account for the time it takes, queue it up for later output, pull incoming characters into a receive queue using a UART ISR, or something like that.

\$\endgroup\$
  • \$\begingroup\$ Could've sworn I tried it w/o the printf()'s! I think I just ended up thrashing between different approaches to debugging this that. In the end, you were right on the money. I've experimented a little and it seems like you really cannot have anything in the read loop! Thanks Chris & other users! \$\endgroup\$ – Thomas R Jun 9 '16 at 0:42
  • \$\begingroup\$ As little as one printf after sending, before the receive loop is enough to throw it off! \$\endgroup\$ – Thomas R Jun 9 '16 at 0:50
1
\$\begingroup\$

I agree with Chris Stratton that their is an impossibly large amount of logging.

Also the code appears to block itself with an infinite while(1) {} loop:

while (1) {
    uint8_t recvChar;
    if (HAL_UART_Receive(&Device_UART_Handle, &recvChar, 1, 5000) != HAL_OK) {
        printf("    Recv fail\r\n");
        printf("    RXNE: %d ORE: %d NE: %d FE: %d PE: %d\r\n",
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_RXNE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_ORE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_NE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_FE),
            __HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_PE));
        while(1) {}  // <================= block everything forever?
    }
    printf("    Recv %d\r\n", recvChar);
}

when it gets an error.

Is that what you meant to happen? If this triggers, due to the logging taking too long, it's stuck forever.

Edit: (from my comment):
Ff you have control of the code at both ends of the UART connection (STM32 and ESP8266), then implement a protocol which ensures their are no lost bytes.

For example, send an acknowledge on each received byte. This would make it more complex, but also make it robust while using debug statements.

This looks like a classic "Heisenberg effect", where their are time sensitive processes, but observing them introduces hard to define delays.

An alternative approach to the logging printfs, which would be much quicker and so have less impact, would be to switch LEDs on when an errors are detected, and when a valid transmission is detected.

\$\endgroup\$
  • \$\begingroup\$ Regarding the outer loop -- I'm doing that simply so I can see how many characters I get. The code I posted is a test case I've put together. The inner loop is just to stop the world after I hit the error condition. \$\endgroup\$ – Thomas R Jun 9 '16 at 0:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.