HardwareSerial.cpp
1 /* UART (hardware serial) for Teensy & Teensy++ 2 * http://www.pjrc.com/teensy/ 3 * Copyright (c) 2008 PJRC.COM, LLC 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 * THE SOFTWARE. 22 */ 23 24 #include <avr/io.h> 25 #include <avr/interrupt.h> 26 #include "core_pins.h" 27 #include "HardwareSerial.h" 28 29 #define RX_BUFFER_SIZE 64 30 static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; 31 static volatile uint8_t rx_buffer_head = 0; 32 static volatile uint8_t rx_buffer_tail = 0; 33 34 #define TX_BUFFER_SIZE 40 35 static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; 36 static volatile uint8_t tx_buffer_head = 0; 37 static volatile uint8_t tx_buffer_tail = 0; 38 static volatile uint8_t transmitting = 0; 39 static volatile uint8_t tx_enable_pin = 255; 40 41 // Public Methods ////////////////////////////////////////////////////////////// 42 43 void HardwareSerial::_begin(uint16_t baud_count, uint8_t txen_pin) 44 { 45 tx_enable_pin = txen_pin; 46 if (txen_pin < 255) { 47 pinMode(txen_pin, OUTPUT); 48 digitalWrite(txen_pin, LOW); 49 } 50 if ((baud_count & 1) && baud_count <= 4096) { 51 UCSR1A = (1<<U2X1); 52 UBRR1 = baud_count - 1; 53 } else { 54 UCSR1A = 0; 55 UBRR1 = (baud_count >> 1) - 1; 56 } 57 if (!(UCSR1B & (1<<TXEN1))) { 58 rx_buffer_head = 0; 59 rx_buffer_tail = 0; 60 tx_buffer_head = 0; 61 tx_buffer_tail = 0; 62 transmitting = 0; 63 UCSR1C = (1<<UCSZ11) | (1<<UCSZ10); 64 UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1); 65 } 66 } 67 68 void HardwareSerial::end(void) 69 { 70 while (transmitting) ; // wait for buffered data to send 71 UCSR1B = 0; 72 rx_buffer_head = 0; 73 rx_buffer_tail = 0; 74 } 75 76 void HardwareSerial::transmitterEnable(uint8_t pin) 77 { 78 while (transmitting) ; 79 pinMode(pin, OUTPUT); 80 digitalWrite(pin, LOW); 81 tx_enable_pin = pin; 82 } 83 84 int HardwareSerial::available(void) 85 { 86 uint8_t head, tail; 87 88 head = rx_buffer_head; 89 tail = rx_buffer_tail; 90 if (head >= tail) return head - tail; 91 return RX_BUFFER_SIZE + head - tail; 92 } 93 94 int HardwareSerial::peek(void) 95 { 96 uint8_t head, tail; 97 98 head = rx_buffer_head; 99 tail = rx_buffer_tail; 100 if (head == tail) return -1; 101 if (++tail >= RX_BUFFER_SIZE) tail = 0; 102 return rx_buffer[tail]; 103 } 104 105 int HardwareSerial::read(void) 106 { 107 uint8_t c, i; 108 109 if (rx_buffer_head == rx_buffer_tail) return -1; 110 i = rx_buffer_tail + 1; 111 if (i >= RX_BUFFER_SIZE) i = 0; 112 c = rx_buffer[i]; 113 rx_buffer_tail = i; 114 return c; 115 } 116 117 void HardwareSerial::flush() 118 { 119 #if ARDUINO >= 100 120 while (transmitting) ; // wait for buffered data to send 121 #else 122 rx_buffer_head = rx_buffer_tail; 123 #endif 124 } 125 126 void HardwareSerial::clear() 127 { 128 rx_buffer_head = rx_buffer_tail; 129 } 130 131 #if ARDUINO >= 100 132 size_t HardwareSerial::write(uint8_t c) 133 #else 134 void HardwareSerial::write(uint8_t c) 135 #endif 136 { 137 uint8_t i; 138 139 if (!(UCSR1B & (1<<TXEN1))) { 140 #if ARDUINO >= 100 141 setWriteError(); 142 return 0; 143 #else 144 return; 145 #endif 146 } 147 if (tx_enable_pin < 255 && !transmitting) { 148 digitalWrite(tx_enable_pin, HIGH); 149 } 150 i = tx_buffer_head + 1; 151 if (i >= TX_BUFFER_SIZE) i = 0; 152 while (tx_buffer_tail == i) ; // wait until space in buffer 153 tx_buffer[i] = c; 154 transmitting = 1; 155 tx_buffer_head = i; 156 UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1) | (1<<UDRIE1); 157 #if ARDUINO >= 100 158 return 1; 159 #endif 160 } 161 162 ISR(USART1_RX_vect) 163 { 164 uint8_t c, i; 165 166 c = UDR1; 167 i = rx_buffer_head + 1; 168 if (i >= RX_BUFFER_SIZE) i = 0; 169 if (i != rx_buffer_tail) { 170 rx_buffer[i] = c; 171 rx_buffer_head = i; 172 } 173 } 174 175 ISR(USART1_UDRE_vect) 176 { 177 uint8_t i; 178 179 if (tx_buffer_head == tx_buffer_tail) { 180 // buffer is empty, disable transmit interrupt 181 UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1); 182 } else { 183 i = tx_buffer_tail + 1; 184 if (i >= TX_BUFFER_SIZE) i = 0; 185 UDR1 = tx_buffer[i]; 186 tx_buffer_tail = i; 187 } 188 } 189 190 ISR(USART1_TX_vect) 191 { 192 transmitting = 0; 193 if (tx_enable_pin < 255) { 194 digitalWrite(tx_enable_pin, LOW); 195 } 196 } 197 198 // Preinstantiate Objects ////////////////////////////////////////////////////// 199 200 HardwareSerial Serial1; 201 202 203