diff options
author | David A. Mellis <d.mellis@arduino.cc> | 2009-08-15 14:48:42 +0000 |
---|---|---|
committer | David A. Mellis <d.mellis@arduino.cc> | 2009-08-15 14:48:42 +0000 |
commit | 50f77c7210a490d8fee28348fcda811ca0bdf615 (patch) | |
tree | c5ed76441bcdd7c51b6bf07d7b0ba16444dbaee6 /cores/arduino/HardwareSerial.cpp | |
parent | 159051b8f814edb7474912ad6d04058d34f2d173 (diff) | |
parent | 79b7ecdd92973f4aa67a6bcaa8bd12a10e5b5133 (diff) |
Moving the processing-5503 branch (used for Arduino 0017) into the trunk.
Diffstat (limited to 'cores/arduino/HardwareSerial.cpp')
-rwxr-xr-x | cores/arduino/HardwareSerial.cpp | 124 |
1 files changed, 76 insertions, 48 deletions
diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index f8a959a..1af6a66 100755 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -49,41 +49,41 @@ ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; inline void store_char(unsigned char c, ring_buffer *rx_buffer) { - int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; - - // if we should be storing the received character into the location - // just before the tail (meaning that the head would advance to the - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - if (i != rx_buffer->tail) { - rx_buffer->buffer[rx_buffer->head] = c; - rx_buffer->head = i; - } + int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != rx_buffer->tail) { + rx_buffer->buffer[rx_buffer->head] = c; + rx_buffer->head = i; + } } #if defined(__AVR_ATmega1280__) SIGNAL(SIG_USART0_RECV) { - unsigned char c = UDR0; + unsigned char c = UDR0; store_char(c, &rx_buffer); } SIGNAL(SIG_USART1_RECV) { - unsigned char c = UDR1; + unsigned char c = UDR1; store_char(c, &rx_buffer1); } SIGNAL(SIG_USART2_RECV) { - unsigned char c = UDR2; + unsigned char c = UDR2; store_char(c, &rx_buffer2); } SIGNAL(SIG_USART3_RECV) { - unsigned char c = UDR3; + unsigned char c = UDR3; store_char(c, &rx_buffer3); } @@ -96,9 +96,9 @@ SIGNAL(USART_RX_vect) #endif { #if defined(__AVR_ATmega8__) - unsigned char c = UDR; + unsigned char c = UDR; #else - unsigned char c = UDR0; + unsigned char c = UDR0; #endif store_char(c, &rx_buffer); } @@ -111,7 +111,7 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, volatile uint8_t *ucsra, volatile uint8_t *ucsrb, volatile uint8_t *udr, - uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre) + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x) { _rx_buffer = rx_buffer; _ubrrh = ubrrh; @@ -123,14 +123,43 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, _txen = txen; _rxcie = rxcie; _udre = udre; + _u2x = u2x; } // Public Methods ////////////////////////////////////////////////////////////// -void HardwareSerial::begin(long speed) +void HardwareSerial::begin(long baud) { - *_ubrrh = ((F_CPU / 16 + speed / 2) / speed - 1) >> 8; - *_ubrrl = ((F_CPU / 16 + speed / 2) / speed - 1); + uint16_t baud_setting; + bool use_u2x; + + // U2X mode is needed for baud rates higher than (CPU Hz / 16) + if (baud > F_CPU / 16) { + use_u2x = true; + } else { + // figure out if U2X mode would allow for a better connection + + // calculate the percent difference between the baud-rate specified and + // the real baud rate for both U2X and non-U2X mode (0-255 error percent) + uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud))); + uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud))); + + // prefer non-U2X mode because it handles clock skew better + use_u2x = (nonu2x_baud_error > u2x_baud_error); + } + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + sbi(*_ucsrb, _rxen); sbi(*_ucsrb, _txen); sbi(*_ucsrb, _rxcie); @@ -138,54 +167,53 @@ void HardwareSerial::begin(long speed) uint8_t HardwareSerial::available(void) { - return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; + return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; } int HardwareSerial::read(void) { - // if the head isn't ahead of the tail, we don't have any characters - if (_rx_buffer->head == _rx_buffer->tail) { - return -1; - } else { - unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; - _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; - return c; - } + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; + return c; + } } void HardwareSerial::flush() { - // don't reverse this or there may be problems if the RX interrupt - // occurs after reading the value of rx_buffer_head but before writing - // the value to rx_buffer_tail; the previous value of rx_buffer_head - // may be written to rx_buffer_tail, making it appear as if the buffer - // don't reverse this or there may be problems if the RX interrupt - // occurs after reading the value of rx_buffer_head but before writing - // the value to rx_buffer_tail; the previous value of rx_buffer_head - // may be written to rx_buffer_tail, making it appear as if the buffer - // were full, not empty. - _rx_buffer->head = _rx_buffer->tail; + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // were full, not empty. + _rx_buffer->head = _rx_buffer->tail; } void HardwareSerial::write(uint8_t c) { - while (!((*_ucsra) & (1 << _udre))) - ; + while (!((*_ucsra) & (1 << _udre))) + ; - *_udr = c; + *_udr = c; } // Preinstantiate Objects ////////////////////////////////////////////////////// #if defined(__AVR_ATmega8__) -HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE); +HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X); #else -HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0); +HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0); #endif #if defined(__AVR_ATmega1280__) -HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1); -HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2); -HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3); +HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1); +HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2); +HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3); #endif - |