Teensy 4.1 core updated for C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
4.6KB

  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. #include <avr/io.h>
  24. #include <avr/interrupt.h>
  25. #include "core_pins.h"
  26. #include "HardwareSerial.h"
  27. #define RX_BUFFER_SIZE 64
  28. static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
  29. static volatile uint8_t rx_buffer_head = 0;
  30. static volatile uint8_t rx_buffer_tail = 0;
  31. #define TX_BUFFER_SIZE 40
  32. static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];
  33. static volatile uint8_t tx_buffer_head = 0;
  34. static volatile uint8_t tx_buffer_tail = 0;
  35. static volatile uint8_t transmitting = 0;
  36. static volatile uint8_t tx_enable_pin = 255;
  37. // Public Methods //////////////////////////////////////////////////////////////
  38. void HardwareSerial::_begin(uint16_t baud_count, uint8_t txen_pin)
  39. {
  40. tx_enable_pin = txen_pin;
  41. if (txen_pin < 255) {
  42. pinMode(txen_pin, OUTPUT);
  43. digitalWrite(txen_pin, LOW);
  44. }
  45. if ((baud_count & 1) && baud_count <= 4096) {
  46. UCSR1A = (1<<U2X1);
  47. UBRR1 = baud_count - 1;
  48. } else {
  49. UCSR1A = 0;
  50. UBRR1 = (baud_count >> 1) - 1;
  51. }
  52. if (!(UCSR1B & (1<<TXEN1))) {
  53. rx_buffer_head = 0;
  54. rx_buffer_tail = 0;
  55. tx_buffer_head = 0;
  56. tx_buffer_tail = 0;
  57. transmitting = 0;
  58. UCSR1C = (1<<UCSZ11) | (1<<UCSZ10);
  59. UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1);
  60. }
  61. }
  62. void HardwareSerial::end(void)
  63. {
  64. while (transmitting) ; // wait for buffered data to send
  65. UCSR1B = 0;
  66. rx_buffer_head = 0;
  67. rx_buffer_tail = 0;
  68. }
  69. int HardwareSerial::available(void)
  70. {
  71. uint8_t head, tail;
  72. head = rx_buffer_head;
  73. tail = rx_buffer_tail;
  74. if (head >= tail) return head - tail;
  75. return RX_BUFFER_SIZE + head - tail;
  76. }
  77. int HardwareSerial::peek(void)
  78. {
  79. uint8_t head, tail;
  80. head = rx_buffer_head;
  81. tail = rx_buffer_tail;
  82. if (head == tail) return -1;
  83. if (++tail >= RX_BUFFER_SIZE) tail = 0;
  84. return rx_buffer[tail];
  85. }
  86. int HardwareSerial::read(void)
  87. {
  88. uint8_t c, i;
  89. if (rx_buffer_head == rx_buffer_tail) return -1;
  90. i = rx_buffer_tail + 1;
  91. if (i >= RX_BUFFER_SIZE) i = 0;
  92. c = rx_buffer[i];
  93. rx_buffer_tail = i;
  94. return c;
  95. }
  96. void HardwareSerial::flush()
  97. {
  98. #if ARDUINO >= 100
  99. while (transmitting) ; // wait for buffered data to send
  100. #else
  101. rx_buffer_head = rx_buffer_tail;
  102. #endif
  103. }
  104. void HardwareSerial::clear()
  105. {
  106. rx_buffer_head = rx_buffer_tail;
  107. }
  108. #if ARDUINO >= 100
  109. size_t HardwareSerial::write(uint8_t c)
  110. #else
  111. void HardwareSerial::write(uint8_t c)
  112. #endif
  113. {
  114. uint8_t i;
  115. if (!(UCSR1B & (1<<TXEN1))) {
  116. #if ARDUINO >= 100
  117. setWriteError();
  118. return 0;
  119. #else
  120. return;
  121. #endif
  122. }
  123. if (tx_enable_pin < 255 && !transmitting) {
  124. digitalWrite(tx_enable_pin, HIGH);
  125. }
  126. i = tx_buffer_head + 1;
  127. if (i >= TX_BUFFER_SIZE) i = 0;
  128. while (tx_buffer_tail == i) ; // wait until space in buffer
  129. tx_buffer[i] = c;
  130. transmitting = 1;
  131. tx_buffer_head = i;
  132. UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1) | (1<<UDRIE1);
  133. #if ARDUINO >= 100
  134. return 1;
  135. #endif
  136. }
  137. ISR(USART1_RX_vect)
  138. {
  139. uint8_t c, i;
  140. c = UDR1;
  141. i = rx_buffer_head + 1;
  142. if (i >= RX_BUFFER_SIZE) i = 0;
  143. if (i != rx_buffer_tail) {
  144. rx_buffer[i] = c;
  145. rx_buffer_head = i;
  146. }
  147. }
  148. ISR(USART1_UDRE_vect)
  149. {
  150. uint8_t i;
  151. if (tx_buffer_head == tx_buffer_tail) {
  152. // buffer is empty, disable transmit interrupt
  153. UCSR1B = (1<<RXEN1) | (1<<TXCIE1) | (1<<TXEN1) | (1<<RXCIE1);
  154. } else {
  155. i = tx_buffer_tail + 1;
  156. if (i >= TX_BUFFER_SIZE) i = 0;
  157. UDR1 = tx_buffer[i];
  158. tx_buffer_tail = i;
  159. }
  160. }
  161. ISR(USART1_TX_vect)
  162. {
  163. transmitting = 0;
  164. if (tx_enable_pin < 255) {
  165. digitalWrite(tx_enable_pin, LOW);
  166. }
  167. }
  168. // Preinstantiate Objects //////////////////////////////////////////////////////
  169. HardwareSerial Serial1;