No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

439 líneas
12KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2017 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "kinetis.h"
  31. #include "core_pins.h"
  32. #include "HardwareSerial.h"
  33. #include <stddef.h>
  34. #ifdef HAS_KINETISK_UART4
  35. ////////////////////////////////////////////////////////////////
  36. // Tunable parameters (relatively safe to edit these numbers)
  37. ////////////////////////////////////////////////////////////////
  38. #ifndef SERIAL5_TX_BUFFER_SIZE
  39. #define SERIAL5_TX_BUFFER_SIZE 40 // number of outgoing bytes to buffer
  40. #endif
  41. #ifndef SERIAL5_RX_BUFFER_SIZE
  42. #define SERIAL5_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer
  43. #endif
  44. #define RTS_HIGH_WATERMARK (SERIAL5_RX_BUFFER_SIZE-24) // RTS requests sender to pause
  45. #define RTS_LOW_WATERMARK (SERIAL5_RX_BUFFER_SIZE-38) // RTS allows sender to resume
  46. #define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest
  47. ////////////////////////////////////////////////////////////////
  48. // changes not recommended below this point....
  49. ////////////////////////////////////////////////////////////////
  50. #ifdef SERIAL_9BIT_SUPPORT
  51. static uint8_t use9Bits = 0;
  52. #define BUFTYPE uint16_t
  53. #else
  54. #define BUFTYPE uint8_t
  55. #define use9Bits 0
  56. #endif
  57. static volatile BUFTYPE tx_buffer[SERIAL5_TX_BUFFER_SIZE];
  58. static volatile BUFTYPE rx_buffer[SERIAL5_RX_BUFFER_SIZE];
  59. static volatile BUFTYPE *rx_buffer_storage_ = NULL;
  60. static volatile BUFTYPE *tx_buffer_storage_ = NULL;
  61. static size_t tx_buffer_total_size_ = SERIAL5_TX_BUFFER_SIZE;
  62. static size_t rx_buffer_total_size_ = SERIAL5_RX_BUFFER_SIZE;
  63. static size_t rts_low_watermark_ = RTS_LOW_WATERMARK;
  64. static size_t rts_high_watermark_ = RTS_HIGH_WATERMARK;
  65. static volatile uint8_t transmitting = 0;
  66. static volatile uint8_t *transmit_pin=NULL;
  67. #define transmit_assert() *transmit_pin = 1
  68. #define transmit_deassert() *transmit_pin = 0
  69. static volatile uint8_t *rts_pin=NULL;
  70. #define rts_assert() *rts_pin = 0
  71. #define rts_deassert() *rts_pin = 1
  72. #if SERIAL5_TX_BUFFER_SIZE > 65535
  73. static volatile uint32_t tx_buffer_head = 0;
  74. static volatile uint32_t tx_buffer_tail = 0;
  75. #elif SERIAL5_TX_BUFFER_SIZE > 255
  76. static volatile uint16_t tx_buffer_head = 0;
  77. static volatile uint16_t tx_buffer_tail = 0;
  78. #else
  79. static volatile uint8_t tx_buffer_head = 0;
  80. static volatile uint8_t tx_buffer_tail = 0;
  81. #endif
  82. #if SERIAL5_RX_BUFFER_SIZE > 65535
  83. static volatile uint32_t rx_buffer_head = 0;
  84. static volatile uint32_t rx_buffer_tail = 0;
  85. #elif SERIAL5_RX_BUFFER_SIZE > 255
  86. static volatile uint16_t rx_buffer_head = 0;
  87. static volatile uint16_t rx_buffer_tail = 0;
  88. #else
  89. static volatile uint8_t rx_buffer_head = 0;
  90. static volatile uint8_t rx_buffer_tail = 0;
  91. #endif
  92. static uint8_t tx_pin_num = 33;
  93. // UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS
  94. // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer
  95. #define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE
  96. #define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE
  97. #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
  98. #define C2_TX_INACTIVE C2_ENABLE
  99. void serial5_begin(uint32_t divisor)
  100. {
  101. SIM_SCGC1 |= SIM_SCGC1_UART4; // turn on clock, TODO: use bitband
  102. rx_buffer_head = 0;
  103. rx_buffer_tail = 0;
  104. tx_buffer_head = 0;
  105. tx_buffer_tail = 0;
  106. transmitting = 0;
  107. CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3);
  108. CORE_PIN33_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  109. if (divisor < 32) divisor = 32;
  110. UART4_BDH = (divisor >> 13) & 0x1F;
  111. UART4_BDL = (divisor >> 5) & 0xFF;
  112. UART4_C4 = divisor & 0x1F;
  113. UART4_C1 = 0;
  114. UART4_PFIFO = 0;
  115. UART4_C2 = C2_TX_INACTIVE;
  116. NVIC_SET_PRIORITY(IRQ_UART4_STATUS, IRQ_PRIORITY);
  117. NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
  118. }
  119. void serial5_format(uint32_t format)
  120. {
  121. uint8_t c;
  122. c = UART4_C1;
  123. c = (c & ~0x13) | (format & 0x03); // configure parity
  124. if (format & 0x04) c |= 0x10; // 9 bits (might include parity)
  125. UART4_C1 = c;
  126. if ((format & 0x0F) == 0x04) UART4_C3 |= 0x40; // 8N2 is 9 bit with 9th bit always 1
  127. c = UART4_S2 & ~0x10;
  128. if (format & 0x10) c |= 0x10; // rx invert
  129. UART4_S2 = c;
  130. c = UART4_C3 & ~0x10;
  131. if (format & 0x20) c |= 0x10; // tx invert
  132. UART4_C3 = c;
  133. #ifdef SERIAL_9BIT_SUPPORT
  134. c = UART4_C4 & 0x1F;
  135. if (format & 0x08) c |= 0x20; // 9 bit mode with parity (requires 10 bits)
  136. UART4_C4 = c;
  137. use9Bits = format & 0x80;
  138. #endif
  139. // For T3.5/T3.6 See about turning on 2 stop bit mode
  140. if ( format & 0x100) {
  141. uint8_t bdl = UART4_BDL;
  142. UART4_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud
  143. UART4_BDL = bdl; // Says BDH not acted on until BDL is written
  144. }
  145. }
  146. void serial5_end(void)
  147. {
  148. if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return;
  149. while (transmitting) yield(); // wait for buffered data to send
  150. NVIC_DISABLE_IRQ(IRQ_UART4_STATUS);
  151. UART4_C2 = 0;
  152. CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1);
  153. CORE_PIN33_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1);
  154. UART4_S1;
  155. UART4_D; // clear leftover error status
  156. rx_buffer_head = 0;
  157. rx_buffer_tail = 0;
  158. if (rts_pin) rts_deassert();
  159. }
  160. void serial5_set_transmit_pin(uint8_t pin)
  161. {
  162. while (transmitting) ;
  163. pinMode(pin, OUTPUT);
  164. digitalWrite(pin, LOW);
  165. transmit_pin = portOutputRegister(pin);
  166. }
  167. void serial5_set_tx(uint8_t pin, uint8_t opendrain)
  168. {
  169. uint32_t cfg;
  170. if (opendrain) pin |= 128;
  171. if (pin == tx_pin_num) return;
  172. if ((SIM_SCGC1 & SIM_SCGC1_UART4)) {
  173. switch (tx_pin_num & 127) {
  174. case 33: CORE_PIN33_CONFIG = 0; break; // PTE24
  175. }
  176. if (opendrain) {
  177. cfg = PORT_PCR_DSE | PORT_PCR_ODE;
  178. } else {
  179. cfg = PORT_PCR_DSE | PORT_PCR_SRE;
  180. }
  181. switch (pin & 127) {
  182. case 33: CORE_PIN33_CONFIG = cfg | PORT_PCR_MUX(3); break;
  183. }
  184. }
  185. tx_pin_num = pin;
  186. }
  187. void serial5_set_rx(uint8_t pin)
  188. {
  189. }
  190. int serial5_set_rts(uint8_t pin)
  191. {
  192. if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return 0;
  193. if (pin < CORE_NUM_DIGITAL) {
  194. rts_pin = portOutputRegister(pin);
  195. pinMode(pin, OUTPUT);
  196. rts_assert();
  197. } else {
  198. rts_pin = NULL;
  199. return 0;
  200. }
  201. return 1;
  202. }
  203. int serial5_set_cts(uint8_t pin)
  204. {
  205. if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return 0;
  206. if (pin == 24) {
  207. CORE_PIN24_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_PE; // weak pulldown
  208. } else {
  209. UART4_MODEM &= ~UART_MODEM_TXCTSE;
  210. return 0;
  211. }
  212. UART4_MODEM |= UART_MODEM_TXCTSE;
  213. return 1;
  214. }
  215. void serial5_putchar(uint32_t c)
  216. {
  217. uint32_t head, n;
  218. if (!(SIM_SCGC1 & SIM_SCGC1_UART4)) return;
  219. if (transmit_pin) transmit_assert();
  220. head = tx_buffer_head;
  221. if (++head >= tx_buffer_total_size_) head = 0;
  222. while (tx_buffer_tail == head) {
  223. int priority = nvic_execution_priority();
  224. if (priority <= IRQ_PRIORITY) {
  225. if ((UART4_S1 & UART_S1_TDRE)) {
  226. uint32_t tail = tx_buffer_tail;
  227. if (++tail >= tx_buffer_total_size_) tail = 0;
  228. if (tail < SERIAL5_TX_BUFFER_SIZE) {
  229. n = tx_buffer[tail];
  230. } else {
  231. n = tx_buffer_storage_[tail-SERIAL5_TX_BUFFER_SIZE];
  232. }
  233. if (use9Bits) UART4_C3 = (UART4_C3 & ~0x40) | ((n & 0x100) >> 2);
  234. UART4_D = n;
  235. tx_buffer_tail = tail;
  236. }
  237. } else if (priority >= 256) {
  238. yield(); // wait
  239. }
  240. }
  241. if (head < SERIAL5_TX_BUFFER_SIZE) {
  242. tx_buffer[head] = c;
  243. } else {
  244. tx_buffer_storage_[head - SERIAL5_TX_BUFFER_SIZE] = c;
  245. }
  246. transmitting = 1;
  247. tx_buffer_head = head;
  248. UART4_C2 = C2_TX_ACTIVE;
  249. }
  250. void serial5_write(const void *buf, unsigned int count)
  251. {
  252. const uint8_t *p = (const uint8_t *)buf;
  253. while (count-- > 0) serial5_putchar(*p++);
  254. }
  255. void serial5_flush(void)
  256. {
  257. while (transmitting) yield(); // wait
  258. }
  259. int serial5_write_buffer_free(void)
  260. {
  261. uint32_t head, tail;
  262. head = tx_buffer_head;
  263. tail = tx_buffer_tail;
  264. if (head >= tail) return tx_buffer_total_size_ - 1 - head + tail;
  265. return tail - head - 1;
  266. }
  267. int serial5_available(void)
  268. {
  269. uint32_t head, tail;
  270. head = rx_buffer_head;
  271. tail = rx_buffer_tail;
  272. if (head >= tail) return head - tail;
  273. return rx_buffer_total_size_ + head - tail;
  274. }
  275. int serial5_getchar(void)
  276. {
  277. uint32_t head, tail;
  278. int c;
  279. head = rx_buffer_head;
  280. tail = rx_buffer_tail;
  281. if (head == tail) return -1;
  282. if (++tail >= rx_buffer_total_size_) tail = 0;
  283. if (tail < SERIAL5_RX_BUFFER_SIZE) {
  284. c = rx_buffer[tail];
  285. } else {
  286. c = rx_buffer_storage_[tail-SERIAL5_RX_BUFFER_SIZE];
  287. }
  288. rx_buffer_tail = tail;
  289. if (rts_pin) {
  290. int avail;
  291. if (head >= tail) avail = head - tail;
  292. else avail = rx_buffer_total_size_ + head - tail;
  293. if (avail <= rts_low_watermark_) rts_assert();
  294. }
  295. return c;
  296. }
  297. int serial5_peek(void)
  298. {
  299. uint32_t head, tail;
  300. head = rx_buffer_head;
  301. tail = rx_buffer_tail;
  302. if (head == tail) return -1;
  303. if (++tail >= rx_buffer_total_size_) tail = 0;
  304. if (tail < SERIAL5_RX_BUFFER_SIZE) {
  305. return rx_buffer[tail];
  306. }
  307. return rx_buffer_storage_[tail-SERIAL5_RX_BUFFER_SIZE];
  308. }
  309. void serial5_clear(void)
  310. {
  311. rx_buffer_head = rx_buffer_tail;
  312. if (rts_pin) rts_assert();
  313. }
  314. // status interrupt combines
  315. // Transmit data below watermark UART_S1_TDRE
  316. // Transmit complete UART_S1_TC
  317. // Idle line UART_S1_IDLE
  318. // Receive data above watermark UART_S1_RDRF
  319. // LIN break detect UART_S2_LBKDIF
  320. // RxD pin active edge UART_S2_RXEDGIF
  321. void uart4_status_isr(void)
  322. {
  323. uint32_t head, tail, n;
  324. uint8_t c;
  325. if (UART4_S1 & UART_S1_RDRF) {
  326. if (use9Bits && (UART4_C3 & 0x80)) {
  327. n = UART4_D | 0x100;
  328. } else {
  329. n = UART4_D;
  330. }
  331. head = rx_buffer_head + 1;
  332. if (head >= rx_buffer_total_size_) head = 0;
  333. if (head != rx_buffer_tail) {
  334. if (head < SERIAL5_RX_BUFFER_SIZE) {
  335. rx_buffer[head] = n;
  336. } else {
  337. rx_buffer_storage_[head-SERIAL5_RX_BUFFER_SIZE] = n;
  338. }
  339. rx_buffer_head = head;
  340. }
  341. if (rts_pin) {
  342. int avail;
  343. tail = tx_buffer_tail;
  344. if (head >= tail) avail = head - tail;
  345. else avail = rx_buffer_total_size_ + head - tail;
  346. if (avail >= rts_high_watermark_) rts_deassert();
  347. }
  348. }
  349. c = UART4_C2;
  350. if ((c & UART_C2_TIE) && (UART4_S1 & UART_S1_TDRE)) {
  351. head = tx_buffer_head;
  352. tail = tx_buffer_tail;
  353. if (head == tail) {
  354. UART4_C2 = C2_TX_COMPLETING;
  355. } else {
  356. if (++tail >= tx_buffer_total_size_) tail = 0;
  357. if (tail < SERIAL5_TX_BUFFER_SIZE) {
  358. n = tx_buffer[tail];
  359. } else {
  360. n = tx_buffer_storage_[tail-SERIAL5_TX_BUFFER_SIZE];
  361. }
  362. if (use9Bits) UART4_C3 = (UART4_C3 & ~0x40) | ((n & 0x100) >> 2);
  363. UART4_D = n;
  364. tx_buffer_tail = tail;
  365. }
  366. }
  367. if ((c & UART_C2_TCIE) && (UART4_S1 & UART_S1_TC)) {
  368. transmitting = 0;
  369. if (transmit_pin) transmit_deassert();
  370. UART4_C2 = C2_TX_INACTIVE;
  371. }
  372. }
  373. void serial5_add_memory_for_read(void *buffer, size_t length)
  374. {
  375. rx_buffer_storage_ = (BUFTYPE*)buffer;
  376. if (buffer) {
  377. rx_buffer_total_size_ = SERIAL5_RX_BUFFER_SIZE + length;
  378. } else {
  379. rx_buffer_total_size_ = SERIAL5_RX_BUFFER_SIZE;
  380. }
  381. rts_low_watermark_ = RTS_LOW_WATERMARK + length;
  382. rts_high_watermark_ = RTS_HIGH_WATERMARK + length;
  383. }
  384. void serial5_add_memory_for_write(void *buffer, size_t length)
  385. {
  386. tx_buffer_storage_ = (BUFTYPE*)buffer;
  387. if (buffer) {
  388. tx_buffer_total_size_ = SERIAL5_TX_BUFFER_SIZE + length;
  389. } else {
  390. tx_buffer_total_size_ = SERIAL5_TX_BUFFER_SIZE;
  391. }
  392. }
  393. #endif // HAS_KINETISK_UART4