Skip to content

Way to check if Serial.write() will block or way to have it fail instead of block. [imported] #672

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

Closed
cmaglie opened this issue Nov 15, 2012 · 3 comments
Milestone

Comments

@cmaglie
Copy link
Member

cmaglie commented Nov 15, 2012

This is Issue 672 moved from a Google Code project.
Added by 2011-10-08T16:59:01.000Z by [email protected].
Please review that bug for more context and additional comments, but update this bug.

Original labels: Type-Defect, Priority-Medium, Component-Core

Original description

What steps will reproduce the problem?

  1. Use Arduino RC1.
  2. Download the code attached, and upload it to an Arduino board. (Uno or older, it doesn't matter)
  3. Trigger the interrupt by grounding pin 2, sometimes this takes a few tries.

What is the expected output? What do you see instead?

The interrupt should trigger, but the serial shouldn't print out until the ISR is done under the new scheme of non-blocking serial writes. This happens most of the time.

However, sometimes, when the ISR is triggered, the serial still starts printing a few characters, doesn't finish, and hangs the processor. Even when the pin 2 grounding is removed, and the ISR should finish, it stays stuck there, and I have to use the hardware reset button to get it to work again.

The ISR does not hang the processor when the serial print is removed, so I'm pretty sure the problem is in there somewhere. This all seems to happen more often when the interrupt is rapidly triggered back and forth, though I'm not absolutely sure of this.

What version of the Arduino software are you using? On what operating
system? Which Arduino board are you using?
I'm using Arduino RC1, downloaded on 10/8/11, on MAC OSX 10.6.8. This problem occurs on both the Arduino Uno and the Bare Bones Board clone running the non-optiboot Duemilanove firmware.

@matthijskooijman
Copy link
Collaborator

What I think that happens here is that the the serial buffer fills up when printing from inside an ISR. While the ISR is running, no other interrupts can be triggered, meaning the "byte sent" interrupt from the serial is never triggered, and thus HardwareSerial::write hangs forever waiting for some space in the buffer.

Your proposed fix works, but still requires manual action to make things work. Since this case should be detectable (before entering the wait loop inside HardwareSerial::write you can simply check if interrupts are disabled), I think we can fix this automatically (Automatically discarding data without the user asking for it is of course bad, but it would only happen where it now does a hard lockup, compared to which discarding data is of course perfectly fine). A second alternative that I could imagine is to actually start polling the serial hardware inside the while loop (if we know the interrupt won't fire). Not sure how well that would work, but it would cause the least surprise for anyone debugging an ISR (it would cause additional delays, but people will expect delays, not discarded data and lockups).

@matthijskooijman
Copy link
Collaborator

#1147 points out that calling flush() from an ISR will cause an automatic lockup in the same way, so flush() should probably receive the same treatment.

matthijskooijman added a commit to matthijskooijman/Arduino that referenced this issue Apr 19, 2013
When interrupts are disabled, writing to HardwareSerial could cause a
lockup. When the tx buffer is full, a busy-wait loop is used to wait for
the interrupt handler to free up a byte in the buffer. However, when
interrupts are disabled, this will of course never happen and the
Arduino will lock up. This often caused lockups when doing (big) debug
printing from an interrupt handler.

Additionally, calling flush() with interrupts disabled while
transmission was in progress would also cause a lockup.

When interrupts are disabled, the code now actively checks the UDRE
(UART Data Register Empty) and calls the interrupt handler to free up
room if the bit is set.

This can lead to delays in interrupt handlers when the serial buffer is
full, but a delay is of course always preferred to a lockup.

Closes: arduino#672
References: arduino#1147
matthijskooijman added a commit to matthijskooijman/Arduino that referenced this issue Apr 19, 2013
This introduces two new methods, Serial.setBlocking() and
Serial.getBlocking(), which can be used to enable or disable blocking.

References: arduino#672

---
TODO: This commit is probably not ready to merge, I'm not sure what the proper
API for this feature would be (the current enum approach requires
qualifying the constants with HardwareSerial:: for example). I'm also
not sure where and how to add the new function to a keywords.txt file.
matthijskooijman added a commit to matthijskooijman/Arduino that referenced this issue Dec 18, 2013
When interrupts are disabled, writing to HardwareSerial could cause a
lockup. When the tx buffer is full, a busy-wait loop is used to wait for
the interrupt handler to free up a byte in the buffer. However, when
interrupts are disabled, this will of course never happen and the
Arduino will lock up. This often caused lockups when doing (big) debug
printing from an interrupt handler.

Additionally, calling flush() with interrupts disabled while
transmission was in progress would also cause a lockup.

When interrupts are disabled, the code now actively checks the UDRE
(UART Data Register Empty) and calls the interrupt handler to free up
room if the bit is set.

This can lead to delays in interrupt handlers when the serial buffer is
full, but a delay is of course always preferred to a lockup.

Closes: arduino#672
References: arduino#1147
cmaglie pushed a commit to cmaglie/Arduino that referenced this issue Jan 22, 2014
When interrupts are disabled, writing to HardwareSerial could cause a
lockup. When the tx buffer is full, a busy-wait loop is used to wait for
the interrupt handler to free up a byte in the buffer. However, when
interrupts are disabled, this will of course never happen and the
Arduino will lock up. This often caused lockups when doing (big) debug
printing from an interrupt handler.

Additionally, calling flush() with interrupts disabled while
transmission was in progress would also cause a lockup.

When interrupts are disabled, the code now actively checks the UDRE
(UART Data Register Empty) and calls the interrupt handler to free up
room if the bit is set.

This can lead to delays in interrupt handlers when the serial buffer is
full, but a delay is of course always preferred to a lockup.

Closes: arduino#672
References: arduino#1147
@cmaglie
Copy link
Member Author

cmaglie commented Jan 28, 2014

Merged the fix, to be released in 1.5.6.
C

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants