aboutsummaryrefslogtreecommitdiff
path: root/cores/arduino/HardwareSerial.cpp
AgeCommit message (Collapse)Author
2017-11-13Fix flush hanging issueJohn Holman
Make write to UDR and clearing of TXC bit in flush() atomic to avoid race condition. Fixes #3745 (second different issue introduced later but discussed in the same issue)
2017-11-13Improve how TXCn bit is cleared in USCRnA registerJohn Holman
Preserve values of configuration bits MPCMn and U2Xn. Avoid setting other read-only bits for datasheet conformance. See #3745
2017-11-13Prevent buffer retransmission when transmit buffer is emptyJohn Holman
Moving the head buffer pointer and setting interrupt flag is now atomic in write(). Previously an intervening ISR could empty the buffer before the second ISR is triggered causing retransmission. Fixes: #3745 (original issue only)
2017-11-13Create macro to guard critical sections for large transmit buffersJohn Holman
New macro TX_BUFFER_ATOMIC makes the following code block atomic only if the transmit buffer is larger than 256 bytes. SREG is restored on completion. The macro is then used to simplify code for availableForWrite()
2015-07-31Prevent losing bytes in HardwareSerial::end()Matthijs Kooijman
end() already waited for the buffer to be empty, but then there could still be two bytes in the hardware registers that still need to be transmitted (which were dropped or kept in the buffer, depending on the exact timing). This changes the wait loop to a call to the flush() function, which already takes care of really waiting for all bytes to be transmitted, meaning it is safe to turn off the transmitter.
2015-05-29Saving some bytes in HardwareSerial::writechromhelm
2015-05-21Fixed bug with flushingchromhelm
2014-10-21Merge branch 'master' into ide-1.5.xCristian Maglie
Conflicts: hardware/arduino/cores/arduino/HardwareSerial.cpp hardware/arduino/cores/robot/Arduino.h
2014-10-21Revert "Match return value to type in available()"Cristian Maglie
This reverts commit f40e4713542fa862d5b99b256a642e001a796988. Added an hint for the buffer sizes. See #2057 Fixes #2367
2014-07-18Add availableForWrite() to HardwareSerialPaulStoffregen
2014-05-23Merge branch 'ide-1.5.x-hwserial-cleanup' of ↵Cristian Maglie
github.com:matthijskooijman/Arduino into matthijskooijman-ide-1.5.x-hwserial-cleanup
2014-05-23Merge remote-tracking branch 'arduino/master' into ide-1.5.xCristian Maglie
Conflicts: build/shared/examples/01.Basics/Blink/Blink.ino build/shared/examples/09.USB/Keyboard/KeyboardReprogram/KeyboardReprogram.ino build/shared/examples/10.StarterKit/p02_SpaceshipInterface/p02_SpaceshipInterface.ino hardware/arduino/cores/arduino/HardwareSerial.cpp
2014-05-07Match return value to type in available()Zachary J. Fields
2014-05-06Fix comment typoMatthijs Kooijman
2014-04-01Merge commit '1ad74' into ide-1.5.xCristian Maglie
2014-03-27Fix typo in SerialEvent3 handlingMatthijs Kooijman
In commit 0e97bcb (Put each HardwareSerial instance in its own .cpp file), the serial event handling was changed. This was probably a copy-paste typo. The effect of this bug was that SerialEvent3 would not run, unless SerialEvent2 was defined, but also that if SerialEvent2 is defined but SerialEvent3 is not, this could cause a reset (call to NULL pointer). This closes #1967, thanks to Peter Olson for finding the bug and fix.
2014-03-24Added support for different size of TX and RX buffer sizes.jantje
Added support for buffer sizes bigger than 256 bytes. Added possibility to overrule the default size. Added support for different size of TX and RX buffer sizes. The default values remain the same. You can however specify a different value for TX and RX buffer Added possibility to overrule the default size. If you want to have different values define SERIAL_TX_BUFFER_SIZE and SERIAL_RX_BUFFER_SIZE on the command line Added support for buffer sizes bigger than 256 bytes. Because of the possibility to change the size of the buffer sizes longer than 256 must be supported. The type of the indexes is decided upon the size of the buffers. So there is no increase in program/data size when the buffers are smaller than 257
2014-03-23This commit contains 2 changes:jantje
Added support for different size of TX and RX buffer sizes. Added support for buffer sizes bigger than 256 bytes. Added support for different size of TX and RX buffer sizes. The default values remain the same. If you want to have different values define SERIAL_TX_BUFFER_SIZE and SERIAL_RX_BUFFER_SIZE on the command line Added support for buffer sizes bigger than 256 bytes. The type of the indexes is decided upon the size of the buffers. So there is no increase in program/data size when the buffers are smaller than 257
2014-02-14In HardwareSerial, don't use int for buffer indicesMatthijs Kooijman
The index attributes have been uint8_t for a while, so there is no point in using int for local variables. This should allow the compiler to generate slightly more efficient code, but (at least on gcc 4.8.2) it also confuses the register allocator, causing this change to increase code size by 2 bytes instead due to extra push/pop instructions (but this will probably change in the future if the compiler improves).
2014-02-10Added license for avr/HardwareSerial.Cristian Maglie
See #1847
2014-01-22In HardwareSerial::write, bypass the queue when it's emptyMatthijs Kooijman
This helps improve the effective datarate on high (>500kbit/s) bitrates, by skipping the interrupt and associated overhead. At 1 Mbit/s the implementation previously got up to about 600-700 kbit/s, but now it actually gets up to the 1Mbit/s (values are rough estimates, though).
2014-01-22Inlined HardwareSerial calls to RX ISR.Cristian Maglie
Moreover, declaring pointers-to-registers as const and using initializer list in class constructor allows the compiler to further improve inlining performance. This change recovers about 50 bytes of program space on single-UART devices. See #1711
2014-01-22Put each HardwareSerial instance in its own .cpp fileMatthijs Kooijman
By putting the ISRs and HardwareSerial instance for each instance in a separate compilation unit, the compile will only consider them for linking when the instance is actually used. The ISR is always referenced by the compiler runtime and the Serialx_available() function is always referenced by SerialEventRun(), but both references are weak and thus do not cause the compilation to be included in the link by themselves. The effect of this is that when multiple HardwareSerial ports are available, but not all are used, buffers are only allocated and ISRs are only included for the serial ports that are used. On the mega, this lowers memory usage from 653 bytes to just 182 when only using the first serial port. On boards with just a single port, there is no change, since the code and memory was already left out when no serial port was used at all. This fixes #1425 and fixes #1259.
2014-01-22Centrally decide which hardware UARTS are availableMatthijs Kooijman
Before, this decision was made in few different places, based on sometimes different register defines. Now, HardwareSerial.h decides wich UARTS are available, defines USE_HWSERIALn macros and HardwareSerial.cpp simply checks these macros (together with some #ifs to decide which registers to use for UART 0). For consistency, USBAPI.h also defines a HAVE_CDCSERIAL macro when applicable. For supported targets, this should change any behaviour. For unsupported targets, the error messages might subtly change because some checks are moved or changed. Additionally, this moves the USBAPI.h include form HardareSerial.h into Arduino.h and raises an error when both CDC serial and UART0 are available (previously this would silently use UART0 instead of CDC, but there is not currently any Atmel chip available for which this would occur).
2014-01-22Disable the UDRE interrupt sooner in HardwareSerialMatthijs Kooijman
Before, the interrupt was disabled when it was triggered and it turned out there was no data to send. However, the interrupt can be disabled already when the last byte is written to the UART, since write() will always re-enable the interrupt when it adds new data to the buffer. Closes: #1008
2014-01-22Fix lockup when writing to HardwareSerial with interrupts disabledMatthijs Kooijman
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: #672 References: #1147
2014-01-22Fix HardwareSerial::flush() when interrupts are kept disabled for a whileMatthijs Kooijman
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 #1463 and replaces #1456.
2014-01-22Improve HardwareSerial::flush()Matthijs Kooijman
The flush() method blocks until all characters in the serial buffer have been written to the uart _and_ transmitted. This is checked by waiting until the "TXC" (TX Complete) bit is set by the UART, signalling completion. This bit is cleared by write() when adding a new byte to the buffer and set by the hardware after tranmission ends, so it is always guaranteed to be zero from the moment the first byte in a sequence is queued until the moment the last byte is transmitted, and it is one from the moment the last byte in the buffer is transmitted until the first byte in the next sequence is queued. However, the TXC bit is also zero from initialization to the moment the first byte ever is queued (and then continues to be zero until the first sequence of bytes completes transmission). Unfortunately we cannot manually set the TXC bit during initialization, we can only clear it. To make sure that flush() would not (indefinitely) block when it is called _before_ anything was written to the serial device, the "transmitting" variable was introduced. This variable suggests that it is only true when something is transmitting, which isn't currently the case (it remains true after transmission is complete until flush() is called, for example). Furthermore, there is no need to keep the status of transmission, the only thing needed is to remember if anything has ever been written, so the corner case described above can be detected. This commit improves the code by: - Renaming the "transmitting" variable to _written (making it more clear and following the leading underscore naming convention). - Not resetting the value of _written at the end of flush(), there is no point to this. - Only checking the "_written" value once in flush(), since it can never be toggled off anyway. - Initializing the value of _written in both versions of _begin (though it probably gets initialized to 0 by default anyway, better to be explicit).
2014-01-22Use bit_is_clear in HardwareSerial::flush()Matthijs Kooijman
This is slightly more clear than the previous explicit comparison.
2014-01-16Move interrupt handlers into HardwareSerial classMatthijs Kooijman
The actual interrupt vectors are of course defined as before, but they let new methods in the HardwareSerial class do the actual work. This greatly reduces code duplication and prepares for one of my next commits which requires the tx interrupt handler to be called from another context as well. The actual content of the interrupts handlers was pretty much identical, so that remains unchanged (except that store_char was now only needed once, so it was inlined). Now all access to the buffers are inside the HardwareSerial class, the buffer variables can be made private. One would expect a program size reduction from this change (at least with multiple UARTs), but due to the fact that the interrupt handlers now only have indirect access to a few registers (which previously were just hardcoded in the handlers) and because there is some extra function call overhead, the code size on the uno actually increases by around 70 bytes. On the mega, which has four UARTs, the code size decreases by around 70 bytes.
2014-01-16Use constants for register bit positions in HardwareSerialMatthijs Kooijman
Previously, the constants to use for the bit positions of the various UARTs were passed to the HardwareSerial constructor. However, this meant that whenever these values were used, the had to be indirectly loaded, resulting in extra code overhead. Additionally, since there is no instruction to shift a value by a variable amount, the 1 << x expressions (inside _BV and sbi() / cbi()) would be compiled as a loop instead of being evaluated at compiletime. Now, the HardwareSerial class always uses the constants for the bit positions of UART 0 (and some code is present to make sure these constants exist, even for targets that only have a single unnumbered UART or start at UART1). This was already done for the TXC0 constant, for some reason. For the actual register addresses, this approach does not work, since these are of course different between the different UARTs on a single chip. Of course, always using the UART 0 constants is only correct when the constants are actually identical for the different UARTs. It has been verified that this is currently the case for all targets supported by avr-gcc 4.7.2, and the code contains compile-time checks to verify this for the current target, in case a new target is added for which this does not hold. This verification was done using: for i in TXC RXEN TXEN RXCIE UDRIE U2X UPE; do echo $i; grep --no-filename -r "#define $i[0-9]\? " /usr/lib/avr/include/avr/io* | sed "s/#define $i[0-9]\?\s*\(\S\)\+\s*\(\/\*.*\*\/\)\?$/\1/" | sort | uniq ; done This command shows that the above constants are identical for all uarts on all platforms, except for TXC, which is sometimes 6 and sometimes 0. Further investigation shows that it is always 6, except in io90scr100.h, but that file defines TXC0 with value 6 for the UART and uses TXC with value 0 for some USB-related register. This commit reduces program size on the uno by around 120 bytes.
2014-01-16Simplify HardwareSerial::begin()Matthijs Kooijman
This simplifies the baud rate calculation, removing the need for a goto and shortening the code a bit. Other than that, this code should not use any different settings than before. Code was suggested by Rob Tillaart on github. Closes: #1262
2014-01-16Remove unused variableMatthijs Kooijman
2014-01-16Slightly reduce code utilization by inlining HardwareSerail begin(baud) and ↵Cristian Maglie
operator bool()
2014-01-16Remove duplicate code from HardwareSerial::begin() methods.Matthijs Kooijman
There are two begin methods, one which accepts just a baud rate and uses the default bit settings and one which accepts both a baudrate and a bit config. Previously, both of these contained a complete implementation, but now the former just calls the latter, explicitely passing the default 8N1 configuration. Technically, this causes a small change: Before the UCSRC register was untouched when calling begin(baud), now it is explicitely initialized with 8N1. However, since this is the default configuration for at least the Uno and the Mega (didn't check any others), probably for all avrs, this shouldn't effectively change anything. Given that the Arduino documentation also documents this as the default when none is passed, explicitly setting it is probably a good idea in any case.
2013-09-09Fixed HardwareSerial bug introduced in 1.5.3.Cristian Maglie
Fixes #1568
2013-07-26Move buffers into HardwareSerialMatthijs Kooijman
This removes the need for doing an extra pointer dereference on every access to the buffers, shrinking the code by around 100 bytes. The members for these buffers must be public for now, since the interrupt handlers also need to access them. These can later be made private again. Furthermore, the struct ring_buffer was removed. This allows the all head and tail pointers to be put into the HardwareSerial struct before the actual buffers, so the pointers all end up in the first 32 bytes of the struct that can be accessed using a single instruction (ldd). References: #947
2013-07-26Use uint8_t for HardwareSerial ringbuffer pointersMatthijs Kooijman
Since the buffers aren't bigger than 64 bytes, these values can be smaller. This saves a few bytes of ram, but also saves around 50 bytes of program space, since the values can now be loaded using a single instruction. To prevent problems when people manually increase the buffer size, a compile-time check is added. Closes: #1078
2013-03-29Fix deprecated ISR names for ATmega8.Cristian Maglie
See #881
2013-03-29Removed deprecated interrupt handlersCristian Maglie
Fixes #831 #881 #955 #1123 #1140
2012-11-29Clarifying comment.David A. Mellis
2012-11-29Moving TXCO definition into HardwareSerial.cpp from HardwareSerial.h.David A. Mellis
Otherwise, you get an error when compiling for processors with no serial port because the header file is always compiled. See, for an example of the problem: https://github.com/damellis/attiny/issues/8
2012-08-30Changing setting of the UMSELn bits (for UART mode) and serial config values.David A. Mellis
Before, the UMSELn1 bit was being to set to 1, putting the UART into a reserved mode. Now, we only set the high (0x80) bit to 1 for the ATmega8, which is needed to access UCSRnC (whose i/o address is shared with UBRRH). Also, no longer bitwise-or the new config with the existing register value, because we're actually configuring all the settings in the register. (We're not using UCPOL, but it's supposed to be 0 in asynchronous mode.)
2012-08-30Merge pull request #109 from Alarus/masterDavid A. Mellis
Serial.begin() parameter to set data bits, parity, stop bits.
2012-08-28Serial.flush() waits for last character to be transmitted (michele.mazzucchi)David A. Mellis
http://code.google.com/p/arduino/issues/detail?id=871
2012-08-14Update hardware/arduino/cores/arduino/HardwareSerial.cppAlarus
New Serial.begin(baud, config);
2012-08-14Update hardware/arduino/cores/arduino/HardwareSerial.cppAlarus
New Serial.begin(baud, config);
2012-08-12Update hardware/arduino/cores/arduino/HardwareSerial.cppAlarus
Adding advanced begin (); with the ability to specify the length of bits, parity, stop bits.
2012-08-12Update hardware/arduino/cores/arduino/HardwareSerial.cppAlarus
Adding advanced begin (); with the ability to specify the length of bits, parity, stop bits.
2012-08-12Update hardware/arduino/cores/arduino/HardwareSerial.cppAlarus
Adding advanced begin (); with the ability to specify the length of bits, parity, stop bits.