├── .gitattributes ├── .gitignore ├── 1.0.5 ├── NeoHWSerial.cpp ├── NeoHWSerial.h └── examples │ └── echo │ └── echo.ino ├── 1.6.5r2 ├── NeoHWSerial.cpp ├── NeoHWSerial.h ├── NeoHWSerial0.cpp ├── NeoHWSerial1.cpp ├── NeoHWSerial2.cpp ├── NeoHWSerial3.cpp └── NeoHWSerial_private.h └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /1.0.5/NeoHWSerial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial.h - Hardware serial library 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | Created 2006 Nicholas Zambetti 19 | Modified 28 September 2010 by Mark Sproul 20 | Modified 14 August 2012 by Alarus 21 | Modified 31 October 2015 by SlashDev 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include "Arduino.h" 28 | #include "wiring_private.h" 29 | #include "NeoHWSerial.h" 30 | 31 | // this next line disables the entire NeoHWSerial.cpp, 32 | // this is so I can support Attiny series and any other chip without a uart 33 | #if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H) 34 | 35 | #include "NeoHWSerial.h" 36 | 37 | /* 38 | * on ATmega8, the uart and its bits are not numbered, so there is no "TXC0" 39 | * definition. 40 | */ 41 | #if !defined(TXC0) 42 | #if defined(TXC) 43 | #define TXC0 TXC 44 | #elif defined(TXC1) 45 | // Some devices have uart1 but no uart0 46 | #define TXC0 TXC1 47 | #else 48 | #error TXC0 not definable in NeoHWSerial.h 49 | #endif 50 | #endif 51 | 52 | // Define constants and variables for buffering incoming serial data. We're 53 | // using a ring buffer (I think), in which head is the index of the location 54 | // to which to write the next incoming character and tail is the index of the 55 | // location from which to read. 56 | #if (RAMEND < 1000) 57 | #define SERIAL_BUFFER_SIZE 16 58 | #else 59 | #define SERIAL_BUFFER_SIZE 64 60 | #endif 61 | 62 | struct ring_buffer 63 | { 64 | unsigned char buffer[SERIAL_BUFFER_SIZE]; 65 | volatile unsigned int head; 66 | volatile unsigned int tail; 67 | }; 68 | 69 | #if defined(USBCON) 70 | ring_buffer rx_buffer = { { 0 }, 0, 0}; 71 | ring_buffer tx_buffer = { { 0 }, 0, 0}; 72 | #endif 73 | #if defined(UBRRH) || defined(UBRR0H) 74 | ring_buffer rx_buffer = { { 0 }, 0, 0 }; 75 | ring_buffer tx_buffer = { { 0 }, 0, 0 }; 76 | #endif 77 | #if defined(UBRR1H) 78 | ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; 79 | ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; 80 | #endif 81 | #if defined(UBRR2H) 82 | ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; 83 | ring_buffer tx_buffer2 = { { 0 }, 0, 0 }; 84 | #endif 85 | #if defined(UBRR3H) 86 | ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; 87 | ring_buffer tx_buffer3 = { { 0 }, 0, 0 }; 88 | #endif 89 | 90 | void NeoHWSerial::store_char( uint8_t c ) 91 | { 92 | if (_isr) 93 | _isr( c ); 94 | else { 95 | int i = (unsigned int)(_rx_buffer->head + 1) % SERIAL_BUFFER_SIZE; 96 | 97 | // if we should be storing the received character into the location 98 | // just before the tail (meaning that the head would advance to the 99 | // current location of the tail), we're about to overflow the buffer 100 | // and so we don't write the character or advance the head. 101 | if (i != _rx_buffer->tail) { 102 | _rx_buffer->buffer[ _rx_buffer->head ] = c; 103 | _rx_buffer->head = i; 104 | } 105 | } 106 | } 107 | 108 | #if !defined(USART0_RX_vect) && defined(USART1_RX_vect) 109 | // do nothing - on the 32u4 the first USART is USART1 110 | #else 111 | #if !defined(USART_RX_vect) && !defined(USART0_RX_vect) && \ 112 | !defined(USART_RXC_vect) 113 | #error "Don't know what the Data Received vector is called for the first UART" 114 | #else 115 | #if defined(USART_RX_vect) 116 | ISR(USART_RX_vect) 117 | #elif defined(USART0_RX_vect) 118 | ISR(USART0_RX_vect) 119 | #elif defined(USART_RXC_vect) 120 | ISR(USART_RXC_vect) // ATmega8 121 | #endif 122 | { 123 | #if defined(UDR0) 124 | if (bit_is_clear(UCSR0A, UPE0)) { 125 | unsigned char c = UDR0; 126 | NeoSerial.store_char(c); 127 | } else { 128 | unsigned char c = UDR0; 129 | }; 130 | #elif defined(UDR) 131 | if (bit_is_clear(UCSRA, PE)) { 132 | unsigned char c = UDR; 133 | NeoSerial.store_char(c); 134 | } else { 135 | unsigned char c = UDR; 136 | }; 137 | #else 138 | #error UDR not defined 139 | #endif 140 | } 141 | #endif 142 | #endif 143 | 144 | #if defined(USART1_RX_vect) 145 | ISR(USART1_RX_vect) 146 | { 147 | if (bit_is_clear(UCSR1A, UPE1)) { 148 | unsigned char c = UDR1; 149 | NeoSerial1.store_char(c); 150 | } else { 151 | unsigned char c = UDR1; 152 | }; 153 | } 154 | #endif 155 | 156 | #if defined(USART2_RX_vect) && defined(UDR2) 157 | ISR(USART2_RX_vect) 158 | { 159 | if (bit_is_clear(UCSR2A, UPE2)) { 160 | unsigned char c = UDR2; 161 | NeoSerial2.store_char(c); 162 | } else { 163 | unsigned char c = UDR2; 164 | }; 165 | } 166 | #endif 167 | 168 | #if defined(USART3_RX_vect) && defined(UDR3) 169 | ISR(USART3_RX_vect) 170 | { 171 | if (bit_is_clear(UCSR3A, UPE3)) { 172 | unsigned char c = UDR3; 173 | NeoSerial3.store_char(c); 174 | } else { 175 | unsigned char c = UDR3; 176 | }; 177 | } 178 | #endif 179 | 180 | 181 | #if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect) 182 | // do nothing - on the 32u4 the first USART is USART1 183 | #else 184 | #if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) 185 | #error "Don't know what the Data Register Empty vector is called for the first UART" 186 | #else 187 | #if defined(UART0_UDRE_vect) 188 | ISR(UART0_UDRE_vect) 189 | #elif defined(UART_UDRE_vect) 190 | ISR(UART_UDRE_vect) 191 | #elif defined(USART0_UDRE_vect) 192 | ISR(USART0_UDRE_vect) 193 | #elif defined(USART_UDRE_vect) 194 | ISR(USART_UDRE_vect) 195 | #endif 196 | { 197 | if (tx_buffer.head == tx_buffer.tail) { 198 | // Buffer empty, so disable interrupts 199 | #if defined(UCSR0B) 200 | cbi(UCSR0B, UDRIE0); 201 | #else 202 | cbi(UCSRB, UDRIE); 203 | #endif 204 | } 205 | else { 206 | // There is more data in the output buffer. Send the next byte 207 | unsigned char c = tx_buffer.buffer[tx_buffer.tail]; 208 | tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; 209 | 210 | #if defined(UDR0) 211 | UDR0 = c; 212 | #elif defined(UDR) 213 | UDR = c; 214 | #else 215 | #error UDR not defined 216 | #endif 217 | } 218 | } 219 | #endif 220 | #endif 221 | 222 | #ifdef USART1_UDRE_vect 223 | ISR(USART1_UDRE_vect) 224 | { 225 | if (tx_buffer1.head == tx_buffer1.tail) { 226 | // Buffer empty, so disable interrupts 227 | cbi(UCSR1B, UDRIE1); 228 | } 229 | else { 230 | // There is more data in the output buffer. Send the next byte 231 | unsigned char c = tx_buffer1.buffer[tx_buffer1.tail]; 232 | tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; 233 | 234 | UDR1 = c; 235 | } 236 | } 237 | #endif 238 | 239 | #ifdef USART2_UDRE_vect 240 | ISR(USART2_UDRE_vect) 241 | { 242 | if (tx_buffer2.head == tx_buffer2.tail) { 243 | // Buffer empty, so disable interrupts 244 | cbi(UCSR2B, UDRIE2); 245 | } 246 | else { 247 | // There is more data in the output buffer. Send the next byte 248 | unsigned char c = tx_buffer2.buffer[tx_buffer2.tail]; 249 | tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE; 250 | 251 | UDR2 = c; 252 | } 253 | } 254 | #endif 255 | 256 | #ifdef USART3_UDRE_vect 257 | ISR(USART3_UDRE_vect) 258 | { 259 | if (tx_buffer3.head == tx_buffer3.tail) { 260 | // Buffer empty, so disable interrupts 261 | cbi(UCSR3B, UDRIE3); 262 | } 263 | else { 264 | // There is more data in the output buffer. Send the next byte 265 | unsigned char c = tx_buffer3.buffer[tx_buffer3.tail]; 266 | tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE; 267 | 268 | UDR3 = c; 269 | } 270 | } 271 | #endif 272 | 273 | 274 | // Constructors //////////////////////////////////////////////////////////////// 275 | 276 | NeoHWSerial::NeoHWSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, 277 | volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, 278 | volatile uint8_t *ucsra, volatile uint8_t *ucsrb, 279 | volatile uint8_t *ucsrc, volatile uint8_t *udr, 280 | uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) 281 | { 282 | _rx_buffer = rx_buffer; 283 | _tx_buffer = tx_buffer; 284 | _ubrrh = ubrrh; 285 | _ubrrl = ubrrl; 286 | _ucsra = ucsra; 287 | _ucsrb = ucsrb; 288 | _ucsrc = ucsrc; 289 | _udr = udr; 290 | _rxen = rxen; 291 | _txen = txen; 292 | _rxcie = rxcie; 293 | _udrie = udrie; 294 | _u2x = u2x; 295 | _isr = (isr_t) NULL; 296 | } 297 | 298 | // Public Methods ////////////////////////////////////////////////////////////// 299 | 300 | void NeoHWSerial::begin(unsigned long baud) 301 | { 302 | uint16_t baud_setting; 303 | bool use_u2x = true; 304 | 305 | #if F_CPU == 16000000UL 306 | // hardcoded exception for compatibility with the bootloader shipped 307 | // with the Duemilanove and previous boards and the firmware on the 8U2 308 | // on the Uno and Mega 2560. 309 | if (baud == 57600) { 310 | use_u2x = false; 311 | } 312 | #endif 313 | 314 | try_again: 315 | 316 | if (use_u2x) { 317 | *_ucsra = 1 << _u2x; 318 | baud_setting = (F_CPU / 4 / baud - 1) / 2; 319 | } else { 320 | *_ucsra = 0; 321 | baud_setting = (F_CPU / 8 / baud - 1) / 2; 322 | } 323 | 324 | if ((baud_setting > 4095) && use_u2x) 325 | { 326 | use_u2x = false; 327 | goto try_again; 328 | } 329 | 330 | // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) 331 | *_ubrrh = baud_setting >> 8; 332 | *_ubrrl = baud_setting; 333 | 334 | transmitting = false; 335 | 336 | sbi(*_ucsrb, _rxen); 337 | sbi(*_ucsrb, _txen); 338 | sbi(*_ucsrb, _rxcie); 339 | cbi(*_ucsrb, _udrie); 340 | } 341 | 342 | void NeoHWSerial::begin(unsigned long baud, byte config) 343 | { 344 | uint16_t baud_setting; 345 | uint8_t current_config; 346 | bool use_u2x = true; 347 | 348 | #if F_CPU == 16000000UL 349 | // hardcoded exception for compatibility with the bootloader shipped 350 | // with the Duemilanove and previous boards and the firmware on the 8U2 351 | // on the Uno and Mega 2560. 352 | if (baud == 57600) { 353 | use_u2x = false; 354 | } 355 | #endif 356 | 357 | try_again: 358 | 359 | if (use_u2x) { 360 | *_ucsra = 1 << _u2x; 361 | baud_setting = (F_CPU / 4 / baud - 1) / 2; 362 | } else { 363 | *_ucsra = 0; 364 | baud_setting = (F_CPU / 8 / baud - 1) / 2; 365 | } 366 | 367 | if ((baud_setting > 4095) && use_u2x) 368 | { 369 | use_u2x = false; 370 | goto try_again; 371 | } 372 | 373 | // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) 374 | *_ubrrh = baud_setting >> 8; 375 | *_ubrrl = baud_setting; 376 | 377 | //set the data bits, parity, and stop bits 378 | #if defined(__AVR_ATmega8__) 379 | config |= 0x80; // select UCSRC register (shared with UBRRH) 380 | #endif 381 | *_ucsrc = config; 382 | 383 | sbi(*_ucsrb, _rxen); 384 | sbi(*_ucsrb, _txen); 385 | sbi(*_ucsrb, _rxcie); 386 | cbi(*_ucsrb, _udrie); 387 | } 388 | 389 | void NeoHWSerial::end() 390 | { 391 | // wait for transmission of outgoing data 392 | while (_tx_buffer->head != _tx_buffer->tail) 393 | ; 394 | 395 | cbi(*_ucsrb, _rxen); 396 | cbi(*_ucsrb, _txen); 397 | cbi(*_ucsrb, _rxcie); 398 | cbi(*_ucsrb, _udrie); 399 | 400 | // clear any received data 401 | _rx_buffer->head = _rx_buffer->tail; 402 | } 403 | 404 | int NeoHWSerial::available(void) 405 | { 406 | return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; 407 | } 408 | 409 | int NeoHWSerial::peek(void) 410 | { 411 | if (_rx_buffer->head == _rx_buffer->tail) { 412 | return -1; 413 | } else { 414 | return _rx_buffer->buffer[_rx_buffer->tail]; 415 | } 416 | } 417 | 418 | int NeoHWSerial::read(void) 419 | { 420 | // if the head isn't ahead of the tail, we don't have any characters 421 | if (_rx_buffer->head == _rx_buffer->tail) { 422 | return -1; 423 | } else { 424 | unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; 425 | _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; 426 | return c; 427 | } 428 | } 429 | 430 | void NeoHWSerial::flush() 431 | { 432 | // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT 433 | while (transmitting && ! (*_ucsra & _BV(TXC0))); 434 | transmitting = false; 435 | } 436 | 437 | size_t NeoHWSerial::write(uint8_t c) 438 | { 439 | int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; 440 | 441 | // If the output buffer is full, there's nothing for it other than to 442 | // wait for the interrupt handler to empty it a bit 443 | // ???: return 0 here instead? 444 | while (i == _tx_buffer->tail) 445 | ; 446 | 447 | _tx_buffer->buffer[_tx_buffer->head] = c; 448 | _tx_buffer->head = i; 449 | 450 | sbi(*_ucsrb, _udrie); 451 | // clear the TXC bit -- "can be cleared by writing a one to its bit location" 452 | transmitting = true; 453 | sbi(*_ucsra, TXC0); 454 | 455 | return 1; 456 | } 457 | 458 | NeoHWSerial::operator bool() { 459 | return true; 460 | } 461 | 462 | void NeoHWSerial::attachInterrupt( isr_t fn ) 463 | { 464 | uint8_t oldSREG = SREG; 465 | cli(); 466 | _isr = fn; 467 | SREG = oldSREG; 468 | } 469 | 470 | // Preinstantiate Objects ////////////////////////////////////////////////////// 471 | 472 | #if defined(UBRRH) && defined(UBRRL) 473 | NeoHWSerial NeoSerial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X); 474 | #elif defined(UBRR0H) && defined(UBRR0L) 475 | NeoHWSerial NeoSerial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0); 476 | #elif defined(USBCON) 477 | // do nothing - Serial object and buffers are initialized in CDC code 478 | #else 479 | #error no serial port defined (port 0) 480 | #endif 481 | 482 | #if defined(UBRR1H) 483 | NeoHWSerial NeoSerial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1); 484 | #endif 485 | #if defined(UBRR2H) 486 | NeoHWSerial NeoSerial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2); 487 | #endif 488 | #if defined(UBRR3H) 489 | NeoHWSerial NeoSerial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3); 490 | #endif 491 | 492 | #endif // whole file 493 | 494 | -------------------------------------------------------------------------------- /1.0.5/NeoHWSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial.h - Hardware serial library 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | Created 2006 Nicholas Zambetti 19 | Modified 28 September 2010 by Mark Sproul 20 | Modified 14 August 2012 by Alarus 21 | Modified 31 October 2015 by SlashDev 22 | */ 23 | 24 | #ifndef NeoHWSerial_h 25 | #define NeoHWSerial_h 26 | 27 | #include 28 | 29 | #include "Stream.h" 30 | 31 | struct ring_buffer; 32 | 33 | class NeoHWSerial : public Stream 34 | { 35 | private: 36 | NeoHWSerial( const NeoHWSerial & ); 37 | NeoHWSerial & operator =( const NeoHWSerial &); 38 | 39 | ring_buffer *_rx_buffer; 40 | ring_buffer *_tx_buffer; 41 | volatile uint8_t *_ubrrh; 42 | volatile uint8_t *_ubrrl; 43 | volatile uint8_t *_ucsra; 44 | volatile uint8_t *_ucsrb; 45 | volatile uint8_t *_ucsrc; 46 | volatile uint8_t *_udr; 47 | uint8_t _rxen; 48 | uint8_t _txen; 49 | uint8_t _rxcie; 50 | uint8_t _udrie; 51 | uint8_t _u2x; 52 | bool transmitting; 53 | public: 54 | NeoHWSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, 55 | volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, 56 | volatile uint8_t *ucsra, volatile uint8_t *ucsrb, 57 | volatile uint8_t *ucsrc, volatile uint8_t *udr, 58 | uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); 59 | void begin(unsigned long); 60 | void begin(unsigned long, uint8_t); 61 | void end(); 62 | virtual int available(void); 63 | virtual int peek(void); 64 | virtual int read(void); 65 | virtual void flush(void); 66 | virtual size_t write(uint8_t); 67 | inline size_t write(unsigned long n) { return write((uint8_t)n); } 68 | inline size_t write(long n) { return write((uint8_t)n); } 69 | inline size_t write(unsigned int n) { return write((uint8_t)n); } 70 | inline size_t write(int n) { return write((uint8_t)n); } 71 | using Print::write; // pull in write(str) and write(buf, size) from Print 72 | operator bool(); 73 | 74 | typedef void (* isr_t)( uint8_t ); 75 | void attachInterrupt( isr_t fn ); 76 | void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; 77 | 78 | void store_char( uint8_t rx ); 79 | private: 80 | isr_t _isr; 81 | }; 82 | 83 | // Define config for Serial.begin(baud, config); 84 | #define SERIAL_5N1 0x00 85 | #define SERIAL_6N1 0x02 86 | #define SERIAL_7N1 0x04 87 | #define SERIAL_8N1 0x06 88 | #define SERIAL_5N2 0x08 89 | #define SERIAL_6N2 0x0A 90 | #define SERIAL_7N2 0x0C 91 | #define SERIAL_8N2 0x0E 92 | #define SERIAL_5E1 0x20 93 | #define SERIAL_6E1 0x22 94 | #define SERIAL_7E1 0x24 95 | #define SERIAL_8E1 0x26 96 | #define SERIAL_5E2 0x28 97 | #define SERIAL_6E2 0x2A 98 | #define SERIAL_7E2 0x2C 99 | #define SERIAL_8E2 0x2E 100 | #define SERIAL_5O1 0x30 101 | #define SERIAL_6O1 0x32 102 | #define SERIAL_7O1 0x34 103 | #define SERIAL_8O1 0x36 104 | #define SERIAL_5O2 0x38 105 | #define SERIAL_6O2 0x3A 106 | #define SERIAL_7O2 0x3C 107 | #define SERIAL_8O2 0x3E 108 | 109 | #if defined(UBRRH) || defined(UBRR0H) 110 | extern NeoHWSerial NeoSerial; 111 | #elif defined(USBCON) 112 | #include "USBAPI.h" 113 | // extern NeoHWSerial Serial_; 114 | #endif 115 | #if defined(UBRR1H) 116 | extern NeoHWSerial NeoSerial1; 117 | #endif 118 | #if defined(UBRR2H) 119 | extern NeoHWSerial NeoSerial2; 120 | #endif 121 | #if defined(UBRR3H) 122 | extern NeoHWSerial NeoSerial3; 123 | #endif 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /1.0.5/examples/echo/echo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 4 | // Example program to show how to attach to the received character 5 | // interrupt with NeoHWSerial. 6 | // 7 | 8 | static volatile uint16_t count = 0; 9 | 10 | static void char_received( uint8_t c ) 11 | { 12 | // This is a little naughty, as it will try to block 13 | // in this ISR if the tx_buffer is full. For this example, 14 | // we are only sending as many characters as we have received, 15 | // and they arrive at the same rate we are sending them. 16 | NeoSerial.write( c ); 17 | count++; 18 | } 19 | 20 | void setup() 21 | { 22 | NeoSerial.begin( 9600 ); 23 | NeoSerial.attachInterrupt( char_received ); 24 | NeoSerial.println( F("Enter data to echo:") ); 25 | } 26 | 27 | void loop() 28 | { 29 | delay( 1000 ); 30 | 31 | uint8_t oldSREG = SREG; 32 | noInterrupts(); 33 | uint16_t old_count = count; 34 | count = 0; 35 | SREG = oldSREG; 36 | 37 | if (old_count) { 38 | NeoSerial.print( '\n' ); 39 | NeoSerial.print( old_count ); 40 | NeoSerial.println( F(" characters echoed") ); 41 | } else 42 | NeoSerial.print( '.' ); 43 | NeoSerial.flush(); 44 | } -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial.cpp - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 3 December 2013 by Matthijs Kooijman 23 | Modified 2 November 2015 by SlashDev 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "Arduino.h" 31 | 32 | #include 33 | #include 34 | 35 | // this next line disables the entire HardwareSerial.cpp, 36 | // this is so I can support Attiny series and any other chip without a uart 37 | #if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) 38 | 39 | // Actual interrupt handlers ////////////////////////////////////////////////////////////// 40 | 41 | void NeoHWSerial::_tx_udr_empty_irq(void) 42 | { 43 | // If interrupts are enabled, there must be more data in the output 44 | // buffer. Send the next byte 45 | unsigned char c = _tx_buffer[_tx_buffer_tail]; 46 | _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE; 47 | 48 | *_udr = c; 49 | 50 | // clear the TXC bit -- "can be cleared by writing a one to its bit 51 | // location". This makes sure flush() won't return until the bytes 52 | // actually got written 53 | sbi(*_ucsra, TXC0); 54 | 55 | if (_tx_buffer_head == _tx_buffer_tail) { 56 | // Buffer empty, so disable interrupts 57 | cbi(*_ucsrb, UDRIE0); 58 | } 59 | } 60 | 61 | // Public Methods ////////////////////////////////////////////////////////////// 62 | 63 | void NeoHWSerial::begin(unsigned long baud, byte config) 64 | { 65 | // Try u2x mode first 66 | uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2; 67 | *_ucsra = 1 << U2X0; 68 | 69 | // hardcoded exception for 57600 for compatibility with the bootloader 70 | // shipped with the Duemilanove and previous boards and the firmware 71 | // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot 72 | // be > 4095, so switch back to non-u2x mode if the baud rate is too 73 | // low. 74 | if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095)) 75 | { 76 | *_ucsra = 0; 77 | baud_setting = (F_CPU / 8 / baud - 1) / 2; 78 | } 79 | 80 | // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register) 81 | *_ubrrh = baud_setting >> 8; 82 | *_ubrrl = baud_setting; 83 | 84 | _written = false; 85 | 86 | //set the data bits, parity, and stop bits 87 | #if defined(__AVR_ATmega8__) 88 | config |= 0x80; // select UCSRC register (shared with UBRRH) 89 | #endif 90 | *_ucsrc = config; 91 | 92 | sbi(*_ucsrb, RXEN0); 93 | sbi(*_ucsrb, TXEN0); 94 | sbi(*_ucsrb, RXCIE0); 95 | cbi(*_ucsrb, UDRIE0); 96 | } 97 | 98 | void NeoHWSerial::end() 99 | { 100 | // wait for transmission of outgoing data 101 | while (_tx_buffer_head != _tx_buffer_tail) 102 | ; 103 | 104 | cbi(*_ucsrb, RXEN0); 105 | cbi(*_ucsrb, TXEN0); 106 | cbi(*_ucsrb, RXCIE0); 107 | cbi(*_ucsrb, UDRIE0); 108 | 109 | // clear any received data 110 | _rx_buffer_head = _rx_buffer_tail; 111 | } 112 | 113 | int NeoHWSerial::available(void) 114 | { 115 | return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE; 116 | } 117 | 118 | int NeoHWSerial::peek(void) 119 | { 120 | if (_rx_buffer_head == _rx_buffer_tail) { 121 | return -1; 122 | } else { 123 | return _rx_buffer[_rx_buffer_tail]; 124 | } 125 | } 126 | 127 | int NeoHWSerial::read(void) 128 | { 129 | // if the head isn't ahead of the tail, we don't have any characters 130 | if (_rx_buffer_head == _rx_buffer_tail) { 131 | return -1; 132 | } else { 133 | unsigned char c = _rx_buffer[_rx_buffer_tail]; 134 | _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE; 135 | return c; 136 | } 137 | } 138 | 139 | int NeoHWSerial::availableForWrite(void) 140 | { 141 | #if (SERIAL_TX_BUFFER_SIZE>256) 142 | uint8_t oldSREG = SREG; 143 | cli(); 144 | #endif 145 | tx_buffer_index_t head = _tx_buffer_head; 146 | tx_buffer_index_t tail = _tx_buffer_tail; 147 | #if (SERIAL_TX_BUFFER_SIZE>256) 148 | SREG = oldSREG; 149 | #endif 150 | if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; 151 | return tail - head - 1; 152 | } 153 | 154 | void NeoHWSerial::flush() 155 | { 156 | // If we have never written a byte, no need to flush. This special 157 | // case is needed since there is no way to force the TXC (transmit 158 | // complete) bit to 1 during initialization 159 | if (!_written) 160 | return; 161 | 162 | while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) { 163 | if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0)) 164 | // Interrupts are globally disabled, but the DR empty 165 | // interrupt should be enabled, so poll the DR empty flag to 166 | // prevent deadlock 167 | if (bit_is_set(*_ucsra, UDRE0)) 168 | _tx_udr_empty_irq(); 169 | } 170 | // If we get here, nothing is queued anymore (DRIE is disabled) and 171 | // the hardware finished tranmission (TXC is set). 172 | } 173 | 174 | size_t NeoHWSerial::write(uint8_t c) 175 | { 176 | _written = true; 177 | // If the buffer and the data register is empty, just write the byte 178 | // to the data register and be done. This shortcut helps 179 | // significantly improve the effective datarate at high (> 180 | // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. 181 | if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { 182 | *_udr = c; 183 | sbi(*_ucsra, TXC0); 184 | return 1; 185 | } 186 | tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; 187 | 188 | // If the output buffer is full, there's nothing for it other than to 189 | // wait for the interrupt handler to empty it a bit 190 | while (i == _tx_buffer_tail) { 191 | if (bit_is_clear(SREG, SREG_I)) { 192 | // Interrupts are disabled, so we'll have to poll the data 193 | // register empty flag ourselves. If it is set, pretend an 194 | // interrupt has happened and call the handler to free up 195 | // space for us. 196 | if(bit_is_set(*_ucsra, UDRE0)) 197 | _tx_udr_empty_irq(); 198 | } else { 199 | // nop, the interrupt handler will free up space for us 200 | } 201 | } 202 | 203 | _tx_buffer[_tx_buffer_head] = c; 204 | _tx_buffer_head = i; 205 | 206 | sbi(*_ucsrb, UDRIE0); 207 | 208 | return 1; 209 | } 210 | 211 | void NeoHWSerial::attachInterrupt( isr_t fn ) 212 | { 213 | uint8_t oldSREG = SREG; 214 | cli(); 215 | _isr = fn; 216 | SREG = oldSREG; 217 | } 218 | 219 | #endif // whole file 220 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial.h - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 28 September 2010 by Mark Sproul 20 | Modified 14 August 2012 by Alarus 21 | Modified 3 December 2013 by Matthijs Kooijman 22 | Modified 2 November 2015 by SlashDev 23 | */ 24 | 25 | #ifndef NeoHWSerial_h 26 | #define NeoHWSerial_h 27 | 28 | #include 29 | 30 | #include "Stream.h" 31 | 32 | // Define constants and variables for buffering incoming serial data. We're 33 | // using a ring buffer (I think), in which head is the index of the location 34 | // to which to write the next incoming character and tail is the index of the 35 | // location from which to read. 36 | // NOTE: a "power of 2" buffer size is reccomended to dramatically 37 | // optimize all the modulo operations for ring buffers. 38 | #if !defined(SERIAL_TX_BUFFER_SIZE) 39 | #if (RAMEND < 1000) 40 | #define SERIAL_TX_BUFFER_SIZE 16 41 | #else 42 | #define SERIAL_TX_BUFFER_SIZE 64 43 | #endif 44 | #endif 45 | #if !defined(SERIAL_RX_BUFFER_SIZE) 46 | #if (RAMEND < 1000) 47 | #define SERIAL_RX_BUFFER_SIZE 16 48 | #else 49 | #define SERIAL_RX_BUFFER_SIZE 64 50 | #endif 51 | #endif 52 | #if (SERIAL_TX_BUFFER_SIZE>256) 53 | typedef uint16_t tx_buffer_index_t; 54 | #else 55 | typedef uint8_t tx_buffer_index_t; 56 | #endif 57 | #if (SERIAL_RX_BUFFER_SIZE>256) 58 | typedef uint16_t rx_buffer_index_t; 59 | #else 60 | typedef uint8_t rx_buffer_index_t; 61 | #endif 62 | 63 | // Define config for Serial.begin(baud, config); 64 | #define SERIAL_5N1 0x00 65 | #define SERIAL_6N1 0x02 66 | #define SERIAL_7N1 0x04 67 | #define SERIAL_8N1 0x06 68 | #define SERIAL_5N2 0x08 69 | #define SERIAL_6N2 0x0A 70 | #define SERIAL_7N2 0x0C 71 | #define SERIAL_8N2 0x0E 72 | #define SERIAL_5E1 0x20 73 | #define SERIAL_6E1 0x22 74 | #define SERIAL_7E1 0x24 75 | #define SERIAL_8E1 0x26 76 | #define SERIAL_5E2 0x28 77 | #define SERIAL_6E2 0x2A 78 | #define SERIAL_7E2 0x2C 79 | #define SERIAL_8E2 0x2E 80 | #define SERIAL_5O1 0x30 81 | #define SERIAL_6O1 0x32 82 | #define SERIAL_7O1 0x34 83 | #define SERIAL_8O1 0x36 84 | #define SERIAL_5O2 0x38 85 | #define SERIAL_6O2 0x3A 86 | #define SERIAL_7O2 0x3C 87 | #define SERIAL_8O2 0x3E 88 | 89 | class NeoHWSerial : public Stream 90 | { 91 | protected: 92 | volatile uint8_t * const _ubrrh; 93 | volatile uint8_t * const _ubrrl; 94 | volatile uint8_t * const _ucsra; 95 | volatile uint8_t * const _ucsrb; 96 | volatile uint8_t * const _ucsrc; 97 | volatile uint8_t * const _udr; 98 | // Has any byte been written to the UART since begin() 99 | bool _written; 100 | 101 | volatile rx_buffer_index_t _rx_buffer_head; 102 | volatile rx_buffer_index_t _rx_buffer_tail; 103 | volatile tx_buffer_index_t _tx_buffer_head; 104 | volatile tx_buffer_index_t _tx_buffer_tail; 105 | 106 | // Don't put any members after these buffers, since only the first 107 | // 32 bytes of this struct can be accessed quickly using the ldd 108 | // instruction. 109 | unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE]; 110 | unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE]; 111 | 112 | public: 113 | inline NeoHWSerial( 114 | volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, 115 | volatile uint8_t *ucsra, volatile uint8_t *ucsrb, 116 | volatile uint8_t *ucsrc, volatile uint8_t *udr); 117 | void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } 118 | void begin(unsigned long, uint8_t); 119 | void end(); 120 | virtual int available(void); 121 | virtual int peek(void); 122 | virtual int read(void); 123 | int availableForWrite(void); 124 | virtual void flush(void); 125 | virtual size_t write(uint8_t); 126 | inline size_t write(unsigned long n) { return write((uint8_t)n); } 127 | inline size_t write(long n) { return write((uint8_t)n); } 128 | inline size_t write(unsigned int n) { return write((uint8_t)n); } 129 | inline size_t write(int n) { return write((uint8_t)n); } 130 | using Print::write; // pull in write(str) and write(buf, size) from Print 131 | operator bool() { return true; } 132 | 133 | // Interrupt handlers - Not intended to be called externally 134 | inline void _rx_complete_irq(void); 135 | void _tx_udr_empty_irq(void); 136 | 137 | typedef void (* isr_t)( uint8_t ); 138 | void attachInterrupt( isr_t fn ); 139 | void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; 140 | private: 141 | isr_t _isr; 142 | 143 | NeoHWSerial( const NeoHWSerial & ); 144 | NeoHWSerial & operator =( const NeoHWSerial &); 145 | }; 146 | 147 | #if defined(UBRRH) || defined(UBRR0H) 148 | extern NeoHWSerial NeoSerial; 149 | #define HAVE_HWSERIAL0 150 | #endif 151 | #if defined(UBRR1H) 152 | extern NeoHWSerial NeoSerial1; 153 | #define HAVE_HWSERIAL1 154 | #endif 155 | #if defined(UBRR2H) 156 | extern NeoHWSerial NeoSerial2; 157 | #define HAVE_HWSERIAL2 158 | #endif 159 | #if defined(UBRR3H) 160 | extern NeoHWSerial NeoSerial3; 161 | #define HAVE_HWSERIAL3 162 | #endif 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial0.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial0.cpp - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 3 December 2013 by Matthijs Kooijman 23 | Modified 2 November 2015 by SlashDev 24 | */ 25 | 26 | #include "Arduino.h" 27 | #include 28 | #include 29 | 30 | // Each NeoHWSerial is defined in its own file, sine the linker pulls 31 | // in the entire file when any element inside is used. --gc-sections can 32 | // additionally cause unused symbols to be dropped, but ISRs have the 33 | // "used" attribute so are never dropped and they keep the 34 | // NeoHWSerial instance in as well. Putting each instance in its own 35 | // file prevents the linker from pulling in any unused instances in the 36 | // first place. 37 | 38 | #if defined(HAVE_HWSERIAL0) 39 | 40 | #if defined(USART_RX_vect) 41 | ISR(USART_RX_vect) 42 | #elif defined(USART0_RX_vect) 43 | ISR(USART0_RX_vect) 44 | #elif defined(USART_RXC_vect) 45 | ISR(USART_RXC_vect) // ATmega8 46 | #else 47 | #error "Don't know what the Data Received vector is called for NeoSerial" 48 | #endif 49 | { 50 | NeoSerial._rx_complete_irq(); 51 | } 52 | 53 | #if defined(UART0_UDRE_vect) 54 | ISR(UART0_UDRE_vect) 55 | #elif defined(UART_UDRE_vect) 56 | ISR(UART_UDRE_vect) 57 | #elif defined(USART0_UDRE_vect) 58 | ISR(USART0_UDRE_vect) 59 | #elif defined(USART_UDRE_vect) 60 | ISR(USART_UDRE_vect) 61 | #else 62 | #error "Don't know what the Data Register Empty vector is called for Serial" 63 | #endif 64 | { 65 | NeoSerial._tx_udr_empty_irq(); 66 | } 67 | 68 | #if defined(UBRRH) && defined(UBRRL) 69 | NeoHWSerial NeoSerial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); 70 | #else 71 | NeoHWSerial NeoSerial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0); 72 | #endif 73 | 74 | #endif // HAVE_HWSERIAL0 75 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial1.cpp - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 3 December 2013 by Matthijs Kooijman 23 | Modified 2 November 2015 by SlashDev 24 | */ 25 | 26 | #include "Arduino.h" 27 | #include 28 | #include 29 | 30 | // Each NeoHWSerial is defined in its own file, sine the linker pulls 31 | // in the entire file when any element inside is used. --gc-sections can 32 | // additionally cause unused symbols to be dropped, but ISRs have the 33 | // "used" attribute so are never dropped and they keep the 34 | // NeoHWSerial instance in as well. Putting each instance in its own 35 | // file prevents the linker from pulling in any unused instances in the 36 | // first place. 37 | 38 | #if defined(HAVE_HWSERIAL1) 39 | 40 | #if defined(UART1_RX_vect) 41 | ISR(UART1_RX_vect) 42 | #elif defined(USART1_RX_vect) 43 | ISR(USART1_RX_vect) 44 | #else 45 | #error "Don't know what the Data Register Empty vector is called for Serial1" 46 | #endif 47 | { 48 | NeoSerial1._rx_complete_irq(); 49 | } 50 | 51 | #if defined(UART1_UDRE_vect) 52 | ISR(UART1_UDRE_vect) 53 | #elif defined(USART1_UDRE_vect) 54 | ISR(USART1_UDRE_vect) 55 | #else 56 | #error "Don't know what the Data Register Empty vector is called for Serial1" 57 | #endif 58 | { 59 | NeoSerial1._tx_udr_empty_irq(); 60 | } 61 | 62 | NeoHWSerial NeoSerial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); 63 | 64 | #endif // HAVE_HWSERIAL1 65 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial2.cpp - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 3 December 2013 by Matthijs Kooijman 23 | Modified 2 November 2015 by SlashDev 24 | */ 25 | 26 | #include "Arduino.h" 27 | #include 28 | #include 29 | 30 | // Each NeoHWSerial is defined in its own file, sine the linker pulls 31 | // in the entire file when any element inside is used. --gc-sections can 32 | // additionally cause unused symbols to be dropped, but ISRs have the 33 | // "used" attribute so are never dropped and they keep the 34 | // NeoHWSerial instance in as well. Putting each instance in its own 35 | // file prevents the linker from pulling in any unused instances in the 36 | // first place. 37 | 38 | #if defined(HAVE_HWSERIAL2) 39 | 40 | ISR(USART2_RX_vect) 41 | { 42 | NeoSerial2._rx_complete_irq(); 43 | } 44 | 45 | ISR(USART2_UDRE_vect) 46 | { 47 | NeoSerial2._tx_udr_empty_irq(); 48 | } 49 | 50 | NeoHWSerial NeoSerial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); 51 | 52 | #endif // HAVE_HWSERIAL2 53 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial3.cpp - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 3 December 2013 by Matthijs Kooijman 23 | Modified 2 November 2015 by SlashDev 24 | */ 25 | 26 | #include "Arduino.h" 27 | #include 28 | #include 29 | 30 | // Each NeoHWSerial is defined in its own file, sine the linker pulls 31 | // in the entire file when any element inside is used. --gc-sections can 32 | // additionally cause unused symbols to be dropped, but ISRs have the 33 | // "used" attribute so are never dropped and they keep the 34 | // NeoHWSerial instance in as well. Putting each instance in its own 35 | // file prevents the linker from pulling in any unused instances in the 36 | // first place. 37 | 38 | #if defined(HAVE_HWSERIAL3) 39 | 40 | ISR(USART3_RX_vect) 41 | { 42 | NeoSerial3._rx_complete_irq(); 43 | } 44 | 45 | ISR(USART3_UDRE_vect) 46 | { 47 | NeoSerial3._tx_udr_empty_irq(); 48 | } 49 | 50 | NeoHWSerial NeoSerial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); 51 | 52 | #endif // HAVE_HWSERIAL3 53 | -------------------------------------------------------------------------------- /1.6.5r2/NeoHWSerial_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | NeoHWSerial_private.h - Hardware serial library with attachInterrupt 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 23 November 2006 by David A. Mellis 20 | Modified 28 September 2010 by Mark Sproul 21 | Modified 14 August 2012 by Alarus 22 | Modified 2 November 2015 by SlashDev 23 | */ 24 | 25 | #include "wiring_private.h" 26 | 27 | // this next line disables the entire HardwareSerial.cpp, 28 | // this is so I can support Attiny series and any other chip without a uart 29 | #if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) 30 | 31 | // Ensure that the various bit positions we use are available with a 0 32 | // postfix, so we can always use the values for UART0 for all UARTs. The 33 | // alternative, passing the various values for each UART to the 34 | // HardwareSerial constructor also works, but makes the code bigger and 35 | // slower. 36 | #if !defined(TXC0) 37 | #if defined(TXC) 38 | // Some chips like ATmega8 don't have UPE, only PE. The other bits are 39 | // named as expected. 40 | #if !defined(UPE) && defined(PE) 41 | #define UPE PE 42 | #endif 43 | // On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc. 44 | #define TXC0 TXC 45 | #define RXEN0 RXEN 46 | #define TXEN0 TXEN 47 | #define RXCIE0 RXCIE 48 | #define UDRIE0 UDRIE 49 | #define U2X0 U2X 50 | #define UPE0 UPE 51 | #define UDRE0 UDRE 52 | #elif defined(TXC1) 53 | // Some devices have uart1 but no uart0 54 | #define TXC0 TXC1 55 | #define RXEN0 RXEN1 56 | #define TXEN0 TXEN1 57 | #define RXCIE0 RXCIE1 58 | #define UDRIE0 UDRIE1 59 | #define U2X0 U2X1 60 | #define UPE0 UPE1 61 | #define UDRE0 UDRE1 62 | #else 63 | #error No UART found in NeoHWSerial.cpp 64 | #endif 65 | #endif // !defined TXC0 66 | 67 | // Check at compiletime that it is really ok to use the bit positions of 68 | // UART0 for the other UARTs as well, in case these values ever get 69 | // changed for future hardware. 70 | #if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \ 71 | UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \ 72 | UDRE1 != UDRE0) 73 | #error "Not all bit positions for UART1 are the same as for UART0" 74 | #endif 75 | #if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \ 76 | UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \ 77 | UDRE2 != UDRE0) 78 | #error "Not all bit positions for UART2 are the same as for UART0" 79 | #endif 80 | #if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \ 81 | UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \ 82 | UDRE3 != UDRE0) 83 | #error "Not all bit positions for UART3 are the same as for UART0" 84 | #endif 85 | 86 | // Constructors //////////////////////////////////////////////////////////////// 87 | 88 | NeoHWSerial::NeoHWSerial( 89 | volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, 90 | volatile uint8_t *ucsra, volatile uint8_t *ucsrb, 91 | volatile uint8_t *ucsrc, volatile uint8_t *udr) : 92 | _ubrrh(ubrrh), _ubrrl(ubrrl), 93 | _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc), 94 | _udr(udr), 95 | _rx_buffer_head(0), _rx_buffer_tail(0), 96 | _tx_buffer_head(0), _tx_buffer_tail(0), 97 | _isr(0) 98 | { 99 | } 100 | 101 | // Actual interrupt handlers ////////////////////////////////////////////////////////////// 102 | 103 | void NeoHWSerial::_rx_complete_irq(void) 104 | { 105 | if (bit_is_clear(*_ucsra, UPE0)) { 106 | // No Parity error, read byte and store it in the buffer if there is 107 | // room 108 | unsigned char c = *_udr; 109 | if (_isr) 110 | _isr( c ); 111 | else { 112 | rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE; 113 | 114 | // if we should be storing the received character into the location 115 | // just before the tail (meaning that the head would advance to the 116 | // current location of the tail), we're about to overflow the buffer 117 | // and so we don't write the character or advance the head. 118 | if (i != _rx_buffer_tail) { 119 | _rx_buffer[_rx_buffer_head] = c; 120 | _rx_buffer_head = i; 121 | } 122 | } 123 | } else { 124 | // Parity error, read byte but discard it 125 | *_udr; 126 | }; 127 | } 128 | 129 | #endif // whole file 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The **NeoHWSerial** class is a drop-in replacement for the Arduino built-in class `HardwareSerial`. It adds the capability to handle received characters with a user-defined function *during* the RX interrupt. This can improve performance significantly by eliminating all processing associated with storing and retrieving characters in the ring buffer **and** all polling code that constantly checked for new characters: `available` and `read` are unnecessary. 2 | 3 | ### Installation 4 | 5 | 1. Download the NeoHWSerial master zip file. 6 | 2. Extract all files into a tempory working directory. 7 | 3. Create a `NeoHWSerial` subdirectory in your `Arduino/Libraries` directory. 8 | 4. Copy all files from the version number subdirectory that corresponds to your IDE version into the `NeoHWSerial` subdirectory you created in step 1. For example, if you are using Arduino IDE version 1.0.5, copy all files from the extracted `NeoHWSerial-master/1.0.5` subdirectory into your `Arduino/Libraries/NeoHWSerial` subdirectory. 9 | 10 | ### Usage 11 | 12 | To handle all received characters with your function, you must register it with the specific `NeoSerial[n]` instance: 13 | 14 | #include 15 | 16 | volatile uint32_t newlines = 0UL; 17 | 18 | static void handleRxChar( uint8_t c ) 19 | { 20 | if (c == '\n') 21 | newlines++; 22 | } 23 | 24 | void setup() 25 | { 26 | NeoSerial1.attachInterrupt( handleRxChar ); 27 | NeoSerial1.begin( 9600 ); // Instead of 'Serial1' 28 | } 29 | 30 | Remember that the registered function is called from an interrupt context, and it should return as quickly as possible. Taking too much time in the function will cause many unpredictable behaviors, including loss of received data. See the similar warnings for the built-in [`attachInterrupt`](https://www.arduino.cc/en/Reference/AttachInterrupt) for digital pins. 31 | 32 | The registered function will be called from the ISR whenever a character is received. The received character **will not** be stored in the `rx_buffer`, and it **will not** be returned from `read()`. Any characters that were received and buffered before `attachInterrupt` was called remain in `rx_buffer`, and could be retrieved by calling `read()`. 33 | 34 | If `attachInterrupt` is never called, or it is passed a `NULL` function, the normal buffering occurs, and all received characters must be obtained by calling `read()`. 35 | 36 | The original `HardwareSerial` files were modified to include two new methods, `attachInterrupt` and `detachInterrupt`, and one new data member, the private `_isr`: 37 | 38 | ``` 39 | typedef void (* isr_t)( uint8_t ); 40 | void attachInterrupt( isr_t fn ); 41 | void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; 42 | 43 | private: 44 | isr_t _isr; 45 | ``` 46 | 47 | ### NOTES 48 | 49 | To avoid name collisions, all `HardwareSerial` instances are prefixed with "Neo" in this replacement library. All parts of your sketch, including other libraries, must use 50 | 51 | * `NeoSerial` instead of `Serial`, 52 | * `NeoSerial1` instead of `Serial1`, 53 | * `NeoSerial2` instead of `Serial2`, and 54 | * `NeoSerial3` instead of `Serial3`. 55 | 56 | If there are any references to the original `HardwareSerial` instances, you will get one or more linker errors: 57 | 58 | core.a(HardwareSerial.cpp.o): In function `__vector_18': 59 | \hardware\arduino\cores\arduino/HardwareSerial.cpp:115: multiple definition of `__vector_18' 60 | NeoHWSerial\NeoHWSerial.cpp.o: \NeoHWSerial/NeoHWSerial.cpp:116: first defined here 61 | core.a(HardwareSerial.cpp.o): In function `serialEvent()': 62 | \hardware\arduino\cores\arduino/HardwareSerial.cpp:112: multiple definition of `rx_buffer' 63 | NeoHWSerial\NeoHWSerial.cpp.o: \NeoHWSerial/NeoHWSerial.cpp:90: first defined here 64 | 65 | If you see this error, some part of your code is still using `Serial`, `Serial1`, `Serial2` or `Serial3`. Be sure to check all your libraries. 66 | 67 | All `serialEvent` code has been removed, as this modification is intended to solve polling-related problems. `serialEvent` uses a polling technique. 68 | 69 | As new Arduino IDEs are released, new versions will appear in the root of this repository, named with the Arduino IDE version number. 70 | 71 | ### See Also 72 | 73 | If you are also using software serial ports, you may be interested in [NeoICSerial](https://github.com/SlashDevin/NeoICSerial) or [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial). 74 | --------------------------------------------------------------------------------