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.

HardwareSerial.cpp 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #ifdef TARGET_LPC1768
  23. #include "HardwareSerial.h"
  24. #if SERIAL_PORT == 0 || SERIAL_PORT_2 == 0
  25. HardwareSerial Serial = HardwareSerial(LPC_UART0);
  26. #elif SERIAL_PORT == 1 || SERIAL_PORT_2 == 1
  27. HardwareSerial Serial1 = HardwareSerial((LPC_UART_TypeDef *) LPC_UART1);
  28. #elif SERIAL_PORT == 2 || SERIAL_PORT_2 == 2
  29. HardwareSerial Serial2 = HardwareSerial(LPC_UART2);
  30. #elif SERIAL_PORT == 3 || SERIAL_PORT_2 == 3
  31. HardwareSerial Serial3 = HardwareSerial(LPC_UART3);
  32. #endif
  33. void HardwareSerial::begin(uint32_t baudrate) {
  34. UART_CFG_Type UARTConfigStruct;
  35. PINSEL_CFG_Type PinCfg;
  36. UART_FIFO_CFG_Type FIFOConfig;
  37. if (Baudrate == baudrate) return; // No need to re-initialize
  38. if (UARTx == LPC_UART0) {
  39. // Initialize UART0 pin connect
  40. PinCfg.Funcnum = 1;
  41. PinCfg.OpenDrain = 0;
  42. PinCfg.Pinmode = 0;
  43. PinCfg.Pinnum = 2;
  44. PinCfg.Portnum = 0;
  45. PINSEL_ConfigPin(&PinCfg);
  46. PinCfg.Pinnum = 3;
  47. PINSEL_ConfigPin(&PinCfg);
  48. } else if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) {
  49. // Initialize UART1 pin connect
  50. PinCfg.Funcnum = 1;
  51. PinCfg.OpenDrain = 0;
  52. PinCfg.Pinmode = 0;
  53. PinCfg.Pinnum = 15;
  54. PinCfg.Portnum = 0;
  55. PINSEL_ConfigPin(&PinCfg);
  56. PinCfg.Pinnum = 16;
  57. PINSEL_ConfigPin(&PinCfg);
  58. } else if (UARTx == LPC_UART2) {
  59. // Initialize UART2 pin connect
  60. PinCfg.Funcnum = 1;
  61. PinCfg.OpenDrain = 0;
  62. PinCfg.Pinmode = 0;
  63. PinCfg.Pinnum = 10;
  64. PinCfg.Portnum = 0;
  65. PINSEL_ConfigPin(&PinCfg);
  66. PinCfg.Pinnum = 11;
  67. PINSEL_ConfigPin(&PinCfg);
  68. } else if (UARTx == LPC_UART3) {
  69. // Initialize UART2 pin connect
  70. PinCfg.Funcnum = 1;
  71. PinCfg.OpenDrain = 0;
  72. PinCfg.Pinmode = 0;
  73. PinCfg.Pinnum = 0;
  74. PinCfg.Portnum = 0;
  75. PINSEL_ConfigPin(&PinCfg);
  76. PinCfg.Pinnum = 1;
  77. PINSEL_ConfigPin(&PinCfg);
  78. }
  79. /* Initialize UART Configuration parameter structure to default state:
  80. * Baudrate = 9600bps
  81. * 8 data bit
  82. * 1 Stop bit
  83. * None parity
  84. */
  85. UART_ConfigStructInit(&UARTConfigStruct);
  86. // Re-configure baudrate
  87. UARTConfigStruct.Baud_rate = baudrate;
  88. // Initialize eripheral with given to corresponding parameter
  89. UART_Init(UARTx, &UARTConfigStruct);
  90. // Enable and reset the TX and RX FIFOs
  91. UART_FIFOConfigStructInit(&FIFOConfig);
  92. UART_FIFOConfig(UARTx, &FIFOConfig);
  93. // Enable UART Transmit
  94. UART_TxCmd(UARTx, ENABLE);
  95. // Configure Interrupts
  96. UART_IntConfig(UARTx, UART_INTCFG_RBR, ENABLE);
  97. UART_IntConfig(UARTx, UART_INTCFG_RLS, ENABLE);
  98. if (UARTx == LPC_UART0) NVIC_EnableIRQ(UART0_IRQn);
  99. else if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) NVIC_EnableIRQ(UART1_IRQn);
  100. else if (UARTx == LPC_UART2) NVIC_EnableIRQ(UART2_IRQn);
  101. else if (UARTx == LPC_UART3) NVIC_EnableIRQ(UART3_IRQn);
  102. RxQueueWritePos = RxQueueReadPos = 0;
  103. #if TX_BUFFER_SIZE > 0
  104. TxQueueWritePos = TxQueueReadPos = 0;
  105. #endif
  106. // Save the configured baudrate
  107. Baudrate = baudrate;
  108. }
  109. int16_t HardwareSerial::peek() {
  110. int16_t byte = -1;
  111. // Temporarily lock out UART receive interrupts during this read so the UART receive
  112. // interrupt won't cause problems with the index values
  113. UART_IntConfig(UARTx, UART_INTCFG_RBR, DISABLE);
  114. if (RxQueueReadPos != RxQueueWritePos)
  115. byte = RxBuffer[RxQueueReadPos];
  116. // Re-enable UART interrupts
  117. UART_IntConfig(UARTx, UART_INTCFG_RBR, ENABLE);
  118. return byte;
  119. }
  120. int16_t HardwareSerial::read() {
  121. int16_t byte = -1;
  122. // Temporarily lock out UART receive interrupts during this read so the UART receive
  123. // interrupt won't cause problems with the index values
  124. UART_IntConfig(UARTx, UART_INTCFG_RBR, DISABLE);
  125. if (RxQueueReadPos != RxQueueWritePos) {
  126. byte = RxBuffer[RxQueueReadPos];
  127. RxQueueReadPos = (RxQueueReadPos + 1) % RX_BUFFER_SIZE;
  128. }
  129. // Re-enable UART interrupts
  130. UART_IntConfig(UARTx, UART_INTCFG_RBR, ENABLE);
  131. return byte;
  132. }
  133. size_t HardwareSerial::write(uint8_t send) {
  134. #if TX_BUFFER_SIZE > 0
  135. size_t bytes = 0;
  136. uint32_t fifolvl = 0;
  137. // If the Tx Buffer is full, wait for space to clear
  138. if ((TxQueueWritePos+1) % TX_BUFFER_SIZE == TxQueueReadPos) flushTX();
  139. // Temporarily lock out UART transmit interrupts during this read so the UART transmit interrupt won't
  140. // cause problems with the index values
  141. UART_IntConfig(UARTx, UART_INTCFG_THRE, DISABLE);
  142. // LPC17xx.h incorrectly defines FIFOLVL as a uint8_t, when it's actually a 32-bit register
  143. if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) {
  144. fifolvl = *(reinterpret_cast<volatile uint32_t *>(&((LPC_UART1_TypeDef *) UARTx)->FIFOLVL));
  145. } else fifolvl = *(reinterpret_cast<volatile uint32_t *>(&UARTx->FIFOLVL));
  146. // If the queue is empty and there's space in the FIFO, immediately send the byte
  147. if (TxQueueWritePos == TxQueueReadPos && fifolvl < UART_TX_FIFO_SIZE) {
  148. bytes = UART_Send(UARTx, &send, 1, BLOCKING);
  149. }
  150. // Otherwiise, write the byte to the transmit buffer
  151. else if ((TxQueueWritePos+1) % TX_BUFFER_SIZE != TxQueueReadPos) {
  152. TxBuffer[TxQueueWritePos] = send;
  153. TxQueueWritePos = (TxQueueWritePos+1) % TX_BUFFER_SIZE;
  154. bytes++;
  155. }
  156. // Re-enable the TX Interrupt
  157. UART_IntConfig(UARTx, UART_INTCFG_THRE, ENABLE);
  158. return bytes;
  159. #else
  160. return UART_Send(UARTx, &send, 1, BLOCKING);
  161. #endif
  162. }
  163. #if TX_BUFFER_SIZE > 0
  164. void HardwareSerial::flushTX() {
  165. // Wait for the tx buffer and FIFO to drain
  166. while (TxQueueWritePos != TxQueueReadPos && UART_CheckBusy(UARTx) == SET);
  167. }
  168. #endif
  169. size_t HardwareSerial::available() {
  170. return (RxQueueWritePos + RX_BUFFER_SIZE - RxQueueReadPos) % RX_BUFFER_SIZE;
  171. }
  172. void HardwareSerial::flush() {
  173. RxQueueWritePos = 0;
  174. RxQueueReadPos = 0;
  175. }
  176. size_t HardwareSerial::printf(const char *format, ...) {
  177. char RxBuffer[256];
  178. va_list vArgs;
  179. va_start(vArgs, format);
  180. int length = vsnprintf(RxBuffer, 256, format, vArgs);
  181. va_end(vArgs);
  182. if (length > 0 && length < 256) {
  183. for (size_t i = 0; i < (size_t)length; ++i)
  184. write(RxBuffer[i]);
  185. }
  186. return length;
  187. }
  188. void HardwareSerial::IRQHandler() {
  189. uint32_t IIRValue;
  190. uint8_t LSRValue, byte;
  191. IIRValue = UART_GetIntId(UARTx);
  192. IIRValue &= UART_IIR_INTID_MASK; // check bit 1~3, interrupt identification
  193. // Receive Line Status
  194. if (IIRValue == UART_IIR_INTID_RLS) {
  195. LSRValue = UART_GetLineStatus(UARTx);
  196. // Receive Line Status
  197. if (LSRValue & (UART_LSR_OE | UART_LSR_PE | UART_LSR_FE | UART_LSR_RXFE | UART_LSR_BI)) {
  198. // There are errors or break interrupt
  199. // Read LSR will clear the interrupt
  200. Status = LSRValue;
  201. byte = UART_ReceiveByte(UARTx); // Dummy read on RX to clear interrupt, then bail out
  202. return;
  203. }
  204. }
  205. // Receive Data Available
  206. if (IIRValue == UART_IIR_INTID_RDA) {
  207. // Clear the FIFO
  208. while (UART_Receive(UARTx, &byte, 1, NONE_BLOCKING)) {
  209. #if ENABLED(EMERGENCY_PARSER)
  210. emergency_parser.update(emergency_state, byte);
  211. #endif
  212. if ((RxQueueWritePos + 1) % RX_BUFFER_SIZE != RxQueueReadPos) {
  213. RxBuffer[RxQueueWritePos] = byte;
  214. RxQueueWritePos = (RxQueueWritePos + 1) % RX_BUFFER_SIZE;
  215. } else
  216. break;
  217. }
  218. // Character timeout indicator
  219. } else if (IIRValue == UART_IIR_INTID_CTI) {
  220. // Character Time-out indicator
  221. Status |= 0x100; // Bit 9 as the CTI error
  222. }
  223. #if TX_BUFFER_SIZE > 0
  224. if (IIRValue == UART_IIR_INTID_THRE) {
  225. // Disable THRE interrupt
  226. UART_IntConfig(UARTx, UART_INTCFG_THRE, DISABLE);
  227. // Wait for FIFO buffer empty
  228. while (UART_CheckBusy(UARTx) == SET);
  229. // Transfer up to UART_TX_FIFO_SIZE bytes of data
  230. for (int i = 0; i < UART_TX_FIFO_SIZE && TxQueueWritePos != TxQueueReadPos; i++) {
  231. // Move a piece of data into the transmit FIFO
  232. if (UART_Send(UARTx, &TxBuffer[TxQueueReadPos], 1, NONE_BLOCKING)) {
  233. TxQueueReadPos = (TxQueueReadPos+1) % TX_BUFFER_SIZE;
  234. } else break;
  235. }
  236. // If there is no more data to send, disable the transmit interrupt - else enable it or keep it enabled
  237. if (TxQueueWritePos == TxQueueReadPos) {
  238. UART_IntConfig(UARTx, UART_INTCFG_THRE, DISABLE);
  239. } else UART_IntConfig(UARTx, UART_INTCFG_THRE, ENABLE);
  240. }
  241. #endif
  242. }
  243. #ifdef __cplusplus
  244. extern "C" {
  245. #endif
  246. void UART0_IRQHandler(void) {
  247. #if SERIAL_PORT == 0 || SERIAL_PORT_2 == 0
  248. Serial.IRQHandler();
  249. #endif
  250. }
  251. void UART1_IRQHandler(void) {
  252. #if SERIAL_PORT == 1 || SERIAL_PORT_2 == 1
  253. Serial1.IRQHandler();
  254. #endif
  255. }
  256. void UART2_IRQHandler(void) {
  257. #if SERIAL_PORT == 2 || SERIAL_PORT_2 == 2
  258. Serial2.IRQHandler();
  259. #endif
  260. }
  261. void UART3_IRQHandler(void) {
  262. #if SERIAL_PORT == 3 || SERIAL_PORT_2 == 3
  263. Serial3.IRQHandler();
  264. #endif
  265. }
  266. #ifdef __cplusplus
  267. }
  268. #endif
  269. #endif // TARGET_LPC1768