aboutsummaryrefslogtreecommitdiff
path: root/cores/arduino/HardwareSerial.cpp
AgeCommit message (Collapse)Author
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.
2012-04-01added Boolean operators to HardwareSerial and CDC to test whether the port ↵Zach Eveland
is ready to send data. Mostly useful for Leonardo - simple way to test whether the port is actually opened by an application and ready to receive data. For Serial objects attached to real UARTs always returns true.
2012-02-03Making head and tail unsigned to avoid division in serial ISR.David A. Mellis
http://code.google.com/p/arduino/issues/detail?id=776
2011-10-10Fixing more warnings (Paul Stoffregen).David A. Mellis
2011-09-08Merge branch 'new-extension' of https://github.com/arduino/Arduino into ↵Zach Eveland
new-extension Conflicts: build/linux/dist/tools/avrdude.conf
2011-09-07Changing to a simpler mental model for serialEvent (Paul Stoffregen).David A. Mellis
http://code.google.com/p/arduino/issues/detail?id=626
2011-09-05changed baudrate for auto-reset-and-upload back to 1200 bps. specified ↵Zach Eveland
arduino protocol for Leonardo avrdude upload.
2011-09-05Merge branch 'new-extension' of https://github.com/arduino/Arduino into ↵Zach Eveland
new-extension Conflicts: build/macosx/dist/tools-universal.zip build/windows/avr_tools.zip hardware/arduino/cores/arduino/HardwareSerial.cpp
2011-08-31Moving serialEvent() calls from RX interrupts to main for() loop (after loop()).David A. Mellis
http://code.google.com/p/arduino/issues/detail?id=584
2011-08-30Merge branch 'mainline' into new-extensionZach Eveland
2011-08-26Moving write errors out of return value into separate API methods.David A. Mellis
write(), print(), println() now return size_t (and don't use negative values to signal errors). Print adds writeError() for checking for write errors, clearWriteError() to reset the flag to false, and a protected setWriteError() for signalling errors. http://code.google.com/p/arduino/issues/detail?id=598
2011-08-26Changing from long to ssize_t (int) for write(), print(), println() return.David A. Mellis
2011-08-23write(), print(), and println() now return number of bytes written.David A. Mellis
The type is long, and negative values indicate errors. Needs more testing. http://code.google.com/p/arduino/issues/detail?id=551
2011-08-18HW Serial on pins 0 and 1 works. Accessed by Serial1.* methodsZach Eveland
2011-08-11committed USB API, initial HardwareSerial-USBSerial integrationZach Eveland
2011-05-20Fixing 300 baud communication for serial.David A. Mellis
Because UBBR is only 12 bits, we were overflowing it at 300 baud because of the use of the U2X bit. Now we turn off U2X if it would yield a UBBR value that would overflow. Note that this breaks 300 baud communication with the computer on the Uno and Mega 2560 because the 8U2 USB-serial firmware has this same bug (and previously they cancelled each other out). Since, however, it seems more likely that people will need to use 300 baud to communicate with other (legacy) hardware than with the computer, I'm making this change. Issue for 8U2 firmware bug: http://code.google.com/p/arduino/issues/detail?id=542 http://code.google.com/p/arduino/issues/detail?id=522
2011-05-12Small optimization in HardwareSerial.David A. Mellis
begin(long) -> begin(unsigned long) Conflicts: hardware/arduino/cores/arduino/HardwareSerial.h
2011-05-07Adding serialEvent(), serialEvent1(), etc.David A. Mellis
Called from within the serial receive interrupt. These are implemented as an empty weak function in the core that be overridden by the user's sketch. http://code.google.com/p/arduino/issues/detail?id=263
2011-05-07Refactoring the UART0 / USART0 receive interrupt handler.David A. Mellis
2011-05-07Changing Serial.flush() to write outgoing data, not drop incoming data.David A. Mellis
This brings it in line with most other uses of flush(), both in and out of Arduino. http://code.google.com/p/arduino/issues/detail?id=497
2011-03-06Flushing outgoing and incoming data in Serial.end().David A. Mellis
That is, waiting for outgoing data to transmit and dropping any received data.
2011-03-06Fixing race condition in Serial write (Brian Cook).David A. Mellis
2011-03-05Implemented serial transmit buffering.David A. Mellis
Now Serial.write() places characters in the transmit buffer, and the data register empty interrupt reads and transmit them. Based loosely on the implementation here: ftp://wookey.org.uk/arduino. http://code.google.com/p/arduino/issues/detail?id=262
2011-03-01Moving wiring.h contents into Arduino.h.David A. Mellis