/firmware/src/shared/UART.cc

http://github.com/makerbot/G3Firmware · C++ · 292 lines · 208 code · 50 blank · 34 comment · 46 complexity · da411007c39178d5a833a51b4d9f7c3a MD5 · raw file

  1. /*
  2. * Copyright 2010 by Adam Mayer <adam@makerbot.com>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program 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
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>
  16. */
  17. #include "UART.hh"
  18. #include "Pin.hh"
  19. #include <stdint.h>
  20. #include <avr/sfr_defs.h>
  21. #include <avr/interrupt.h>
  22. #include <avr/io.h>
  23. #include <util/delay.h>
  24. #include <avr/io.h>
  25. // TODO: There should be a better way to enable this flag?
  26. #if ASSERT_LINE_FIX
  27. #include "ExtruderBoard.hh"
  28. #endif
  29. // We have to track the number of bytes that have been sent, so that we can filter
  30. // them from our receive buffer later.This is only used for RS485 mode.
  31. volatile uint8_t loopback_bytes = 0;
  32. // We support three platforms: Atmega168 (1 UART), Atmega644, and Atmega1280/2560
  33. #if defined (__AVR_ATmega168__) \
  34. || defined (__AVR_ATmega328P__) \
  35. || defined (__AVR_ATmega644P__) \
  36. || defined (__AVR_ATmega1280__) \
  37. || defined (__AVR_ATmega2560__)
  38. #else
  39. #error UART not implemented on this processor type!
  40. #endif
  41. #if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
  42. #define UBRR_VALUE 25
  43. #define UCSR0A_VALUE 0
  44. #define INIT_SERIAL(uart_) \
  45. { \
  46. UBRR0H = UBRR_VALUE >> 8; \
  47. UBRR0L = UBRR_VALUE & 0xff; \
  48. \
  49. /* set config for uart, explicitly clear TX interrupt flag */ \
  50. UCSR0A = UCSR0A_VALUE | _BV(TXC0); \
  51. UCSR0B = _BV(RXEN0) | _BV(TXEN0); \
  52. UCSR0C = _BV(UCSZ01)|_BV(UCSZ00); \
  53. }
  54. #elif defined (__AVR_ATmega644P__)
  55. #define UBRR_VALUE 25
  56. #define UBRRA_VALUE 0
  57. // Adapted from ancient arduino/wiring rabbit hole
  58. #define INIT_SERIAL(uart_) \
  59. { \
  60. UBRR##uart_##H = UBRR_VALUE >> 8; \
  61. UBRR##uart_##L = UBRR_VALUE & 0xff; \
  62. \
  63. /* set config for uart_ */ \
  64. UCSR##uart_##A = UBRRA_VALUE; \
  65. UCSR##uart_##B = _BV(RXEN##uart_) | _BV(TXEN##uart_); \
  66. UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
  67. }
  68. #elif defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
  69. // Use double-speed mode for more accurate baud rate?
  70. #define UBRR0_VALUE 16 // 115200 baud
  71. #define UBRR1_VALUE 51 // 38400 baud
  72. #define UCSRA_VALUE(uart_) _BV(U2X##uart_)
  73. // Adapted from ancient arduino/wiring rabbit hole
  74. #define INIT_SERIAL(uart_) \
  75. { \
  76. UBRR##uart_##H = UBRR##uart_##_VALUE >> 8; \
  77. UBRR##uart_##L = UBRR##uart_##_VALUE & 0xff; \
  78. \
  79. /* set config for uart_ */ \
  80. UCSR##uart_##A = UCSRA_VALUE(uart_); \
  81. UCSR##uart_##B = _BV(RXEN##uart_) | _BV(TXEN##uart_); \
  82. UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
  83. }
  84. #endif
  85. #define ENABLE_SERIAL_INTERRUPTS(uart_) \
  86. { \
  87. UCSR##uart_##B |= _BV(RXCIE##uart_) | _BV(TXCIE##uart_); \
  88. }
  89. #define DISABLE_SERIAL_INTERRUPTS(uart_) \
  90. { \
  91. UCSR##uart_##B &= ~(_BV(RXCIE##uart_) | _BV(TXCIE##uart_)); \
  92. }
  93. // TODO: Move these definitions to the board files, where they belong.
  94. #if defined (__AVR_ATmega168__) \
  95. || defined (__AVR_ATmega328P__)
  96. UART UART::hostUART(0, RS485);
  97. #elif defined (__AVR_ATmega644P__) \
  98. || defined (__AVR_ATmega1280__) \
  99. || defined (__AVR_ATmega2560__)
  100. UART UART::hostUART(0, RS232);
  101. #if HAS_SLAVE_UART
  102. UART UART::slaveUART(1, RS485);
  103. #endif
  104. #endif
  105. void UART::init_serial() {
  106. if(index_ == 0) {
  107. INIT_SERIAL(0);
  108. }
  109. #if HAS_SLAVE_UART
  110. else {
  111. INIT_SERIAL(1);
  112. }
  113. #endif
  114. }
  115. void UART::send_byte(char data) {
  116. if(index_ == 0) {
  117. UDR0 = data;
  118. }
  119. #if HAS_SLAVE_UART
  120. else {
  121. UDR1 = data;
  122. }
  123. #endif
  124. }
  125. // Transition to a non-transmitting state. This is only used for RS485 mode.
  126. inline void listen() {
  127. // TX_ENABLE_PIN.setValue(false);
  128. TX_ENABLE_PIN.setValue(false);
  129. }
  130. // Transition to a transmitting state
  131. inline void speak() {
  132. TX_ENABLE_PIN.setValue(true);
  133. }
  134. UART::UART(uint8_t index, communication_mode mode) :
  135. index_(index),
  136. mode_(mode),
  137. enabled_(false) {
  138. init_serial();
  139. }
  140. // Subsequent bytes will be triggered by the tx complete interrupt.
  141. void UART::beginSend() {
  142. if (!enabled_) { return; }
  143. if (mode_ == RS485) {
  144. speak();
  145. _delay_us(10);
  146. loopback_bytes = 1;
  147. }
  148. send_byte(out.getNextByteToSend());
  149. }
  150. void UART::enable(bool enabled) {
  151. enabled_ = enabled;
  152. if (index_ == 0) {
  153. if (enabled) { ENABLE_SERIAL_INTERRUPTS(0); }
  154. else { DISABLE_SERIAL_INTERRUPTS(0); }
  155. }
  156. #if HAS_SLAVE_UART
  157. else if (index_ == 1) {
  158. if (enabled) { ENABLE_SERIAL_INTERRUPTS(1); }
  159. else { DISABLE_SERIAL_INTERRUPTS(1); }
  160. }
  161. #endif
  162. if (mode_ == RS485) {
  163. // If this is an RS485 pin, set up the RX and TX enable control lines.
  164. TX_ENABLE_PIN.setDirection(true);
  165. RX_ENABLE_PIN.setDirection(true);
  166. RX_ENABLE_PIN.setValue(false); // Active low
  167. listen();
  168. loopback_bytes = 0;
  169. }
  170. }
  171. // Reset the UART to a listening state. This is important for
  172. // RS485-based comms.
  173. void UART::reset() {
  174. if (mode_ == RS485) {
  175. loopback_bytes = 0;
  176. listen();
  177. }
  178. }
  179. #if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
  180. // Send and receive interrupts
  181. ISR(USART_RX_vect)
  182. {
  183. static uint8_t byte_in;
  184. byte_in = UDR0;
  185. if (loopback_bytes > 0) {
  186. loopback_bytes--;
  187. } else {
  188. UART::getHostUART().in.processByte( byte_in );
  189. // Workaround for buggy hardware: have slave hold line high.
  190. #if ASSERT_LINE_FIX
  191. if (UART::getHostUART().in.isFinished()
  192. && (UART::getHostUART().in.read8(0)
  193. == ExtruderBoard::getBoard().getSlaveID())) {
  194. speak();
  195. }
  196. #endif
  197. }
  198. }
  199. ISR(USART_TX_vect)
  200. {
  201. if (UART::getHostUART().out.isSending()) {
  202. loopback_bytes++;
  203. UDR0 = UART::getHostUART().out.getNextByteToSend();
  204. } else {
  205. listen();
  206. }
  207. }
  208. #elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
  209. // Send and receive interrupts
  210. ISR(USART0_RX_vect)
  211. {
  212. UART::getHostUART().in.processByte( UDR0 );
  213. }
  214. ISR(USART0_TX_vect)
  215. {
  216. if (UART::getHostUART().out.isSending()) {
  217. UDR0 = UART::getHostUART().out.getNextByteToSend();
  218. }
  219. }
  220. #if HAS_SLAVE_UART
  221. ISR(USART1_RX_vect)
  222. {
  223. static uint8_t byte_in;
  224. byte_in = UDR1;
  225. if (loopback_bytes > 0) {
  226. loopback_bytes--;
  227. } else {
  228. UART::getSlaveUART().in.processByte( byte_in );
  229. }
  230. }
  231. ISR(USART1_TX_vect)
  232. {
  233. if (UART::getSlaveUART().out.isSending()) {
  234. loopback_bytes++;
  235. UDR1 = UART::getSlaveUART().out.getNextByteToSend();
  236. } else {
  237. _delay_us(10);
  238. listen();
  239. }
  240. }
  241. #endif
  242. #endif