-
-
Notifications
You must be signed in to change notification settings - Fork 7k
HardwareSerial flush problem #1463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Under what conditions are you calling flush()? With interrupts enabled? Or are you using a very high baudrate perhaps? |
115200 baud. Write 1 char then call flush(), and it locks.
|
I just did a quick try on my Arduino Uno, and the following sketch works
So it seems the problem is not as general as you describe it and thus Could you provide more details about your testcase, perhaps the Does the above sketch work for you? What hardware are you using? |
Mega1280, yes the case is specific, and complicated. Add me on Google+ and
|
Hmm, I don't actually have a Mega to test with, so this might get complicated indeed :-) In any case, I would prefer it if you would explain the problem here in this ticket, so others can also read it. I'm just trying to get the problem clear, I might not be the one to actually investigate or fix it. You suggested a fix in your original report, but that fix is not correct: It reduces the flush() call from "all bytes sent" to "all bytes written to the UART", so with your changes if someone calls flush() and then shuts down the TX pin, he might have missed one or two bytes. I recently created a pile of fixes for HardwareSerial that haven't been merged yet. Perhaps you could see if they fix your problem as well? They're at #1369. Alternatively, there is a deadlock fix for high baudrates, perhaps you're seeing the same problem at lower baudrates for some reason? The proposed fix is at #1456, could you see if that changes anything for you? Having said that, if you think explaining through some messaging platform works better, feel free to join #arduino on the Freenode IRC network. My nickname is blathijs there. |
I'll try that and let you know.
|
#1456 fixes it for me. My guess is that since I am not operating on internal RAM, but instead external RAM, that the extra clock cycles trip the deadlock easier. Consider this a verification that it can happen at lower baud rates under the right conditions, such as mine. Oh and before I forget, The other factor involved here is that I am multitasking on the external RAM as well. Here is the successful output. Task A Read completed, last read result = -1 (20). |
…hile It turns out there is an additional corner case. The analysis in the previous commit wrt to flush() assumes that the data register is always kept filled by the interrupt handler, so the TXC bit won't get set until all the queued bytes have been transmitted. But, when interrupts are disabled for a longer period (for example when an interrupt handler for another device is running for longer than 1-2 byte times), it could happen that the UART stops transmitting while there are still more bytes queued (but these are in the buffer, not in the UDR register, so the UART can't know about them). In this case, the TXC bit would get set, but the transmission is not complete yet. We can easily detect this case by looking at the head and tail pointers, but it seems easier to instead look at the UDRIE bit (the TX interrupt is enabled if and only if there are bytes in the queue). To fix this corner case, this commit: - Checks the UDRIE bit and only if it is unset, looks at the TXC bit. - Moves the clearing of TXC from write() to the tx interrupt handler. This (still) causes the TXC bit to be cleared whenever a byte is queued when the buffer is empty (in this case the tx interrupt will trigger directly after write() is called). It also causes the TXC bit to be cleared whenever transmission is resumed after it halted because interrupts have been disabled for too long. As a side effect, another race condition is prevented. This could occur at very high bitrates, where the transmission would be completed before the code got time to clear the TXC0 register, making the clear happen _after_ the transmission was already complete. With the new code, the clearing of TXC happens directly after writing to the UDR register, while interrupts are disabled, and we can be certain the data transmission needs more time than one instruction to complete. This fixes arduino#1463 and replaces arduino#1456.
…hile It turns out there is an additional corner case. The analysis in the previous commit wrt to flush() assumes that the data register is always kept filled by the interrupt handler, so the TXC bit won't get set until all the queued bytes have been transmitted. But, when interrupts are disabled for a longer period (for example when an interrupt handler for another device is running for longer than 1-2 byte times), it could happen that the UART stops transmitting while there are still more bytes queued (but these are in the buffer, not in the UDR register, so the UART can't know about them). In this case, the TXC bit would get set, but the transmission is not complete yet. We can easily detect this case by looking at the head and tail pointers, but it seems easier to instead look at the UDRIE bit (the TX interrupt is enabled if and only if there are bytes in the queue). To fix this corner case, this commit: - Checks the UDRIE bit and only if it is unset, looks at the TXC bit. - Moves the clearing of TXC from write() to the tx interrupt handler. This (still) causes the TXC bit to be cleared whenever a byte is queued when the buffer is empty (in this case the tx interrupt will trigger directly after write() is called). It also causes the TXC bit to be cleared whenever transmission is resumed after it halted because interrupts have been disabled for too long. As a side effect, another race condition is prevented. This could occur at very high bitrates, where the transmission would be completed before the code got time to clear the TXC0 register, making the clear happen _after_ the transmission was already complete. With the new code, the clearing of TXC happens directly after writing to the UDR register, while interrupts are disabled, and we can be certain the data transmission needs more time than one instruction to complete. This fixes arduino#1463 and replaces arduino#1456.
Merged Matthijs' patch, this should be fixed in 1.5.6. |
HardwareSerial::flush() sits, spins, and never exits.
Mega 1280, Arduino 1.0.5
hardware/arduino/cores/arduino/HardwareSerial.cpp, line 457
replace
while (transmitting && ! (*_ucsra & _BV(TXC0)));
with
while (transmitting && _tx_buffer->head != _tx_buffer->tail);
fixes the issue.
The text was updated successfully, but these errors were encountered: