mcf5_uart.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. /*
  2. * Copyright 2012 by Embedded Technologies s.r.o
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. */
  32. #include <string.h>
  33. #include <arch/m68k.h>
  34. #include <dev/gpio.h>
  35. #include <sys/atom.h>
  36. #include <sys/event.h>
  37. #include <sys/timer.h>
  38. /*!
  39. * \addtogroup xgNutArchM68kColdfireUart
  40. */
  41. /*@{*/
  42. /* Enable Transmit Ready Interrupt. */
  43. #define SET_TXRDY_INTERRUPT() \
  44. { \
  45. reg_uart.uimr |= MCF_UART_UIMR_TXRDY;\
  46. PREVENT_SPURIOUS_INTERRUPT(MCF_UART_UIMR(BASE) = reg_uart.uimr;)\
  47. }
  48. /* Disable Transmit Ready Interrupt. */
  49. #define CLR_TXRDY_INTERRUPT() \
  50. { \
  51. reg_uart.uimr &= ~MCF_UART_UIMR_TXRDY;\
  52. PREVENT_SPURIOUS_INTERRUPT(MCF_UART_UIMR(BASE) = reg_uart.uimr;)\
  53. }
  54. /* Enable Receive Ready Interrupt. */
  55. #define SET_RXRDY_INTERRUPT() \
  56. { \
  57. reg_uart.uimr |= MCF_UART_UIMR_FFULL_RXRDY;\
  58. PREVENT_SPURIOUS_INTERRUPT(MCF_UART_UIMR(BASE) = reg_uart.uimr;)\
  59. }
  60. /* Disable Receive Ready Interrupt. */
  61. #define CLR_RXRDY_INTERRUPT() \
  62. { \
  63. reg_uart.uimr &= ~MCF_UART_UIMR_FFULL_RXRDY;\
  64. PREVENT_SPURIOUS_INTERRUPT(MCF_UART_UIMR(BASE) = reg_uart.uimr;)\
  65. }
  66. /* Disable All Interrupt. */
  67. #define CLR_ALL_INTERRUPT() \
  68. { \
  69. reg_uart.uimr = 0;\
  70. PREVENT_SPURIOUS_INTERRUPT(MCF_UART_UIMR(BASE) = 0;)\
  71. }
  72. /*
  73. * Software Flow Control
  74. */
  75. #ifdef XONXOFF
  76. /*!
  77. * \brief Enables software flow control if not equal zero.
  78. */
  79. static uint_fast8_t flow_control;
  80. /* \brief ASCII code for software flow control, starts transmitter. */
  81. #define ASCII_XON 0x11
  82. /* \brief ASCII code for software flow control, stops transmitter. */
  83. #define ASCII_XOFF 0x13
  84. /* \brief XON transmit pending flag. */
  85. #define XON_PENDING 0x10
  86. /* \brief XOFF transmit pending flag. */
  87. #define XOFF_PENDING 0x20
  88. /* \brief XOFF sent flag. */
  89. #define XOFF_SENT 0x40
  90. /* \brief XOFF received flag. */
  91. #define XOFF_RCVD 0x80
  92. #endif
  93. /*
  94. * Half Duplex Control
  95. */
  96. #ifdef HDX_CTRL_PIN
  97. #ifdef HDX_CTRL_INV
  98. #define HDX_CTRL_FULL() GpioPinSetHigh(HDX_CTRL_PORT, HDX_CTRL_PIN)
  99. #define HDX_CTRL_HALF() GpioPinSetLow(HDX_CTRL_PORT, HDX_CTRL_PIN)
  100. #else
  101. #define HDX_CTRL_FULL() GpioPinSetLow(HDX_CTRL_PORT, HDX_CTRL_PIN)
  102. #define HDX_CTRL_HALF() GpioPinSetHigh(HDX_CTRL_PORT, HDX_CTRL_PIN)
  103. #endif
  104. #else
  105. #define HDX_CTRL_FULL()
  106. #define HDX_CTRL_HALF()
  107. #endif
  108. #ifdef HDX_CTRL_BOARD_SPEC
  109. // TODO
  110. #endif
  111. /*
  112. * RS485 DE/RE Control
  113. */
  114. #ifdef RS485_CTRL_DE_PIN
  115. #ifdef RS485_CTRL_DE_INV
  116. #define RS485_CTRL_TX_ENA() GpioPinSetLow(RS485_CTRL_DE_PORT, RS485_CTRL_DE_PIN)
  117. #define RS485_CTRL_TX_DIS() GpioPinSetHigh(RS485_CTRL_DE_PORT, RS485_CTRL_DE_PIN)
  118. #else
  119. #define RS485_CTRL_TX_ENA() GpioPinSetHigh(RS485_CTRL_DE_PORT, RS485_CTRL_DE_PIN)
  120. #define RS485_CTRL_TX_DIS() GpioPinSetLow(RS485_CTRL_DE_PORT, RS485_CTRL_DE_PIN)
  121. #endif
  122. #else
  123. #define RS485_CTRL_TX_DIS()
  124. #define RS485_CTRL_TX_ENA()
  125. #endif
  126. #ifdef RS485_CTRL_RE_PIN
  127. #ifdef RS485_CTRL_RE_INV
  128. #define RS485_CTRL_RX_ENA() GpioPinSetHigh(RS485_CTRL_RE_PORT, RS485_CTRL_RE_PIN)
  129. #define RS485_CTRL_RX_DIS() GpioPinSetLow(RS485_CTRL_RE_PORT, RS485_CTRL_RE_PIN)
  130. #else
  131. #define RS485_CTRL_RX_ENA() GpioPinSetLow(RS485_CTRL_RE_PORT, RS485_CTRL_RE_PIN)
  132. #define RS485_CTRL_RX_DIS() GpioPinSetHigh(RS485_CTRL_RE_PORT, RS485_CTRL_RE_PIN)
  133. #endif
  134. #else
  135. #define RS485_CTRL_RX_ENA()
  136. #define RS485_CTRL_RX_DIS()
  137. #endif
  138. #ifdef RS485_CTRL_BOARD_SPEC
  139. // TODO
  140. #endif
  141. /*!
  142. * \brief Receiver error flags.
  143. */
  144. static uint8_t rx_errors;
  145. /*!
  146. * \brief Enables half duplex control if not equal zero.
  147. */
  148. static uint_fast8_t hdx_control;
  149. #ifdef RTS_PIN
  150. /*!
  151. * \brief Enables RTS control if not equal zero.
  152. *
  153. * This variable exists only if the hardware configuration defines a
  154. * port bit to control the RTS signal.
  155. */
  156. static uint_fast8_t rts_control;
  157. #endif
  158. #ifdef CTS_PIN
  159. /*!
  160. * \brief Enables CTS sense if not equal zero.
  161. *
  162. * This variable exists only if the hardware configuration defines a
  163. * port bit to sense the CTS signal.
  164. */
  165. static uint_fast8_t cts_sense;
  166. #endif
  167. /*
  168. * \brief USARTn transmit complete interrupt handler.
  169. *
  170. * Used with half duplex communication to switch from tranmit to receive
  171. * mode after the last character has been transmitted.
  172. *
  173. * \param arg Pointer to the device specific control block.
  174. */
  175. static void Mcf5UsartTxEmpty(void *arg)
  176. {
  177. /*
  178. * Switch RS485 bus driver to receive mode
  179. */
  180. RS485_CTRL_TX_DIS();
  181. RS485_CTRL_RX_ENA();
  182. /*
  183. * Enable receiver
  184. */
  185. MCF_UART_UCR(BASE) = MCF_UART_UCR_RX_ENABLED;
  186. /*
  187. * Disable TX interrupt.
  188. */
  189. CLR_TXRDY_INTERRUPT();
  190. }
  191. /*
  192. * \brief USARTn transmit data register empty interrupt handler.
  193. *
  194. * \param arg Pointer to the device specific control block.
  195. */
  196. static void Mcf5UsartTxReady(void *arg)
  197. {
  198. register RINGBUF *rbf = &((USARTDCB *)arg)->dcb_tx_rbf;;
  199. register uint8_t *cp;
  200. #ifdef XONXOFF
  201. /*
  202. * Process pending software flow controls first.
  203. */
  204. if (flow_control & (XON_PENDING | XOFF_PENDING)) {
  205. if (flow_control & XOFF_PENDING) {
  206. MCF_UART_UTB(BASE) = ASCII_XOFF;
  207. flow_control |= XOFF_SENT;
  208. } else {
  209. MCF_UART_UTB(BASE) = ASCII_XON;
  210. flow_control &= ~XOFF_SENT;
  211. }
  212. flow_control &= ~(XON_PENDING | XOFF_PENDING);
  213. return;
  214. }
  215. if (flow_control & XOFF_RCVD) {
  216. /*
  217. * If XOFF has been received, we disable the transmit interrupts
  218. * and return without sending anything.
  219. */
  220. CLR_TXRDY_INTERRUPT();
  221. return;
  222. }
  223. #endif
  224. /*
  225. * Prepare next character for transmitting
  226. */
  227. if (rbf->rbf_cnt) {
  228. /*
  229. * Previous character transmitted successfully
  230. */
  231. rbf->rbf_cnt--;
  232. /*
  233. * Start transmission of the next character and clear TXRDY bit
  234. * in USR register.
  235. */
  236. cp = rbf->rbf_tail;
  237. MCF_UART_UTB(BASE) = *cp;
  238. /*
  239. * Wrap around the buffer pointer if we reached its end.
  240. */
  241. if (++cp == rbf->rbf_last) {
  242. cp = rbf->rbf_start;
  243. }
  244. rbf->rbf_tail = cp;
  245. /*
  246. * Wakeup waiting thread when tx buffer low watermark is reached
  247. */
  248. if (rbf->rbf_cnt == rbf->rbf_lwm) {
  249. NutEventPostFromIrq(&rbf->rbf_que);
  250. NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_WRITE);
  251. }
  252. }
  253. if (rbf->rbf_cnt == 0){
  254. /*
  255. * Nothing left to transmit, wakeup waiting thread
  256. */
  257. NutEventPostFromIrq(&rbf->rbf_que);
  258. NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_WRITE);
  259. /*
  260. * Disable TX interrupt in full-duplex mode.
  261. * In half-duplex mode, TX interrupt will be disabled after last byte
  262. * will be completely shifted out (Mcf5UsartTxEmpty)
  263. */
  264. if (!hdx_control){
  265. CLR_TXRDY_INTERRUPT();
  266. }
  267. }
  268. }
  269. /*
  270. * \brief USARTn receive complete interrupt handler.
  271. *
  272. * \param arg Pointer to the device specific control block.
  273. */
  274. static void Mcf5UsartRxComplete(void *arg) {
  275. register RINGBUF *rbf = &((USARTDCB *)arg)->dcb_rx_rbf;
  276. register size_t cnt;
  277. register uint8_t ch;
  278. uint_fast8_t usr;
  279. uint_fast8_t postEvent = 0;
  280. /*
  281. * Receive all bytes from RxFIFO
  282. */
  283. do {
  284. /*
  285. * Reading the error flags must come first, because reading
  286. * the data register clears the status.
  287. */
  288. usr = MCF_UART_USR(BASE);
  289. /* Record UART Errors */
  290. rx_errors |= usr;
  291. #ifdef RTS_PIN
  292. /*
  293. * Stop receiving if RX buffer is full.
  294. * After UART's RxFIFO went full, RTS signal will be automatically asserted.
  295. */
  296. if (rbf->rbf_cnt >= rbf->rbf_siz) {
  297. if (rts_control) {
  298. CLR_RXRDY_INTERRUPT();
  299. return;
  300. }
  301. }
  302. #endif
  303. /* Receive char from Rx FIFO */
  304. ch = MCF_UART_URB(BASE);
  305. /* Reset TX errors. */
  306. if (usr & MCF_UART_USR_OE) {
  307. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_ERROR;
  308. }
  309. #ifdef XONXOFF
  310. /*
  311. * Handle software handshake. We have to do this before checking the
  312. * buffer, because flow control must work in write-only mode, where
  313. * there is no receive buffer.
  314. */
  315. if (flow_control) {
  316. /* XOFF character disables transmit interrupts. */
  317. if (ch == ASCII_XOFF) {
  318. CLR_TXRDY_INTERRUPT();
  319. flow_control |= XOFF_RCVD;
  320. return;
  321. }
  322. /* XON enables transmit interrupts. */
  323. else if (ch == ASCII_XON) {
  324. SET_TXRDY_INTERRUPT();
  325. flow_control &= ~XOFF_RCVD;
  326. return;
  327. }
  328. }
  329. #endif
  330. /*
  331. * Check buffer overflow.
  332. */
  333. cnt = rbf->rbf_cnt;
  334. if (cnt >= rbf->rbf_siz) {
  335. rx_errors |= MCF_UART_USR_OE;
  336. return;
  337. }
  338. /*
  339. * Wake up waiting threads if this is the first byte in the buffer.
  340. */
  341. if (cnt++ == 0){
  342. postEvent = 1;
  343. }
  344. #ifdef XONXOFF
  345. /*
  346. * Check the high watermark for software handshake. If the number of
  347. * buffered bytes is above this mark, then send XOFF.
  348. */
  349. else if (flow_control) {
  350. if(cnt >= rbf->rbf_hwm) {
  351. if((flow_control & XOFF_SENT) == 0) {
  352. if (MCF_UART_USR(BASE) & MCF_UART_USR_TXRDY) {
  353. MCF_UART_UTB(BASE) = ASCII_XOFF;
  354. flow_control |= XOFF_SENT;
  355. flow_control &= ~XOFF_PENDING;
  356. } else {
  357. flow_control |= XOFF_PENDING;
  358. }
  359. }
  360. }
  361. }
  362. #endif
  363. /*
  364. * Store the character and increment and the ring buffer pointer.
  365. */
  366. *rbf->rbf_head++ = ch;
  367. if (rbf->rbf_head == rbf->rbf_last) {
  368. rbf->rbf_head = rbf->rbf_start;
  369. }
  370. /*
  371. * Update the ring buffer counter.
  372. */
  373. rbf->rbf_cnt = cnt;
  374. } while ( MCF_UART_USR(BASE) & MCF_UART_USR_RXRDY );
  375. /*
  376. * Wakeup waiting threads
  377. */
  378. if (postEvent) {
  379. NutEventPostFromIrq(&rbf->rbf_que);
  380. NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_READ);
  381. }
  382. }
  383. /*!
  384. * \brief USART interrupt handler.
  385. *
  386. * \param arg Pointer to the device specific control block.
  387. */
  388. static void Mcf5UsartInterrupts(void *arg)
  389. {
  390. if (MCF_UART_USR(BASE) & MCF_UART_USR_RXRDY) {
  391. Mcf5UsartRxComplete(arg);
  392. }
  393. if (MCF_UART_USR(BASE) & MCF_UART_USR_TXRDY) {
  394. Mcf5UsartTxReady(arg);
  395. }
  396. if ((MCF_UART_USR(BASE) & MCF_UART_USR_TXEMP) && (hdx_control) && (((USARTDCB *) arg)->dcb_tx_rbf.rbf_cnt == 0)) {
  397. Mcf5UsartTxEmpty(arg);
  398. }
  399. }
  400. /*!
  401. * \brief Carefully enable USART hardware functions.
  402. *
  403. * Always enable transmitter and receiver, even on read-only or
  404. * write-only mode. So we can support software flow control.
  405. */
  406. static void Mcf5UsartEnable(void)
  407. {
  408. NutEnterCritical();
  409. MCF_UART_UCR(BASE) = MCF_UART_UCR_TX_ENABLED;
  410. MCF_UART_UCR(BASE) = MCF_UART_UCR_RX_ENABLED;
  411. SET_TXRDY_INTERRUPT();
  412. SET_RXRDY_INTERRUPT();
  413. NutExitCritical();
  414. }
  415. /*!
  416. * \brief Carefully disable USART hardware functions.
  417. */
  418. static void Mcf5UsartDisable(void)
  419. {
  420. CLR_ALL_INTERRUPT();
  421. /*
  422. * Allow incoming or outgoing character to finish.
  423. */
  424. NutDelay(10);
  425. /*
  426. * Disable USART transmit and receive.
  427. */
  428. MCF_UART_UCR(BASE) = MCF_UART_UCR_TX_DISABLED;
  429. MCF_UART_UCR(BASE) = MCF_UART_UCR_RX_DISABLED;
  430. }
  431. /*!
  432. * \brief Query the USART hardware for the selected speed.
  433. *
  434. * This function is called by ioctl function of the upper level USART
  435. * driver through the USARTDCB jump table.
  436. *
  437. * \return The currently selected baudrate.
  438. */
  439. static uint32_t Mcf5UsartGetSpeed(void)
  440. {
  441. uint16_t sv;
  442. sv = reg_uart.ubg1 << 8 | reg_uart.ubg2;
  443. return NutGetCpuClock() / (32 * sv);
  444. }
  445. /*!
  446. * \brief Set the USART hardware bit rate.
  447. *
  448. * This function is called by ioctl function of the upper level USART
  449. * driver through the USARTDCB jump table.
  450. *
  451. * \param rate Number of bits per second.
  452. *
  453. * \return 0 on success, -1 otherwise.
  454. */
  455. static int Mcf5UsartSetSpeed(uint32_t rate)
  456. {
  457. uint16_t sv;
  458. sv = (uint16_t) (NutGetCpuClock() / (rate * 32));
  459. reg_uart.ubg1 = (uint8_t) ((sv & 0xFF00) >> 8);
  460. reg_uart.ubg2 = (uint8_t) (sv & 0x00FF);
  461. Mcf5UsartDisable();
  462. MCF_UART_UBG1(BASE) = reg_uart.ubg1;
  463. MCF_UART_UBG2(BASE) = reg_uart.ubg2;
  464. Mcf5UsartEnable();
  465. return 0;
  466. }
  467. /*!
  468. * \brief Query the USART hardware for the number of data bits.
  469. *
  470. * This function is called by ioctl function of the upper level USART
  471. * driver through the USARTDCB jump table.
  472. *
  473. * \return The number of data bits set.
  474. */
  475. static uint8_t Mcf5UsartGetDataBits(void)
  476. {
  477. return (reg_uart.umr1 & 0x3) + 5;
  478. }
  479. /*!
  480. * \brief Set the USART hardware to the number of data bits.
  481. *
  482. * This function is called by ioctl function of the upper level USART
  483. * driver through the USARTDCB jump table.
  484. *
  485. * \return 0 on success, -1 otherwise.
  486. */
  487. static int Mcf5UsartSetDataBits(uint8_t bits)
  488. {
  489. reg_uart.umr1 &= ~MCF_UART_UMR_BC(0x3);
  490. switch (bits) {
  491. case 5:
  492. reg_uart.umr1 |= MCF_UART_UMR_BC_5;
  493. break;
  494. case 6:
  495. reg_uart.umr1 |= MCF_UART_UMR_BC_6;
  496. break;
  497. case 7:
  498. reg_uart.umr1 |= MCF_UART_UMR_BC_7;
  499. break;
  500. case 8:
  501. reg_uart.umr1 |= MCF_UART_UMR_BC_8;
  502. break;
  503. }
  504. Mcf5UsartDisable();
  505. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_MR;
  506. MCF_UART_UMR(BASE) = reg_uart.umr1;
  507. Mcf5UsartEnable();
  508. /*
  509. * Verify the result.
  510. */
  511. if (Mcf5UsartGetDataBits() != bits) {
  512. return -1;
  513. }
  514. return 0;
  515. }
  516. /*!
  517. * \brief Query the USART hardware for the parity mode.
  518. *
  519. * This routine is called by ioctl function of the upper level USART
  520. * driver through the USARTDCB jump table.
  521. *
  522. * \return Parity mode, either 0 (disabled), 1 (odd) or 2 (even).
  523. */
  524. static uint8_t Mcf5UsartGetParity(void)
  525. {
  526. switch (reg_uart.umr1 & 0x1C) {
  527. case MCF_UART_UMR_PM_NONE:
  528. return 0;
  529. case MCF_UART_UMR_PM_ODD:
  530. return 1;
  531. case MCF_UART_UMR_PM_EVEN:
  532. return 2;
  533. }
  534. return -1;
  535. }
  536. /*!
  537. * \brief Set the USART hardware to the specified parity mode.
  538. *
  539. * This routine is called by ioctl function of the upper level USART
  540. * driver through the USARTDCB jump table.
  541. *
  542. * \param mode 0 (none), 1 (odd) or 2 (even).
  543. *
  544. * \return 0 on success, -1 otherwise.
  545. */
  546. static int Mcf5UsartSetParity(uint8_t mode)
  547. {
  548. reg_uart.umr1 &= ~MCF_UART_UMR_PM(0x3);
  549. switch (mode) {
  550. case 0:
  551. reg_uart.umr1 |= MCF_UART_UMR_PM_NONE;
  552. break;
  553. case 1:
  554. reg_uart.umr1 |= MCF_UART_UMR_PM_ODD;
  555. break;
  556. case 2:
  557. reg_uart.umr1 |= MCF_UART_UMR_PM_EVEN;
  558. break;
  559. }
  560. Mcf5UsartDisable();
  561. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_MR;
  562. MCF_UART_UMR(BASE) = reg_uart.umr1;
  563. Mcf5UsartEnable();
  564. /*
  565. * Verify the result.
  566. */
  567. if (Mcf5UsartGetParity() != mode) {
  568. return -1;
  569. }
  570. return 0;
  571. }
  572. /*!
  573. * \brief Query the USART hardware for the number of stop bits.
  574. *
  575. * This routine is called by ioctl function of the upper level USART
  576. * driver through the USARTDCB jump table.
  577. *
  578. * \return The number of stop bits set, either 1 or 2.
  579. */
  580. static uint8_t Mcf5UsartGetStopBits(void)
  581. {
  582. switch (reg_uart.umr2 & 0xF) {
  583. case MCF_UART_UMR_SB_STOP_BITS_1:
  584. return 1;
  585. case MCF_UART_UMR_SB_STOP_BITS_2:
  586. return 2;
  587. case MCF_UART_UMR_SB_STOP_BITS_15:
  588. return 15;
  589. }
  590. return -1;
  591. }
  592. /*!
  593. * \brief Set the USART hardware to the number of stop bits.
  594. *
  595. * This routine is called by ioctl function of the upper level USART
  596. * driver through the USARTDCB jump table.
  597. *
  598. * \param stop bits 1, 2 or 15 (1,5).
  599. *
  600. * \return 0 on success, -1 otherwise.
  601. */
  602. static int Mcf5UsartSetStopBits(uint8_t bits)
  603. {
  604. reg_uart.umr2 &= ~0xF;
  605. switch (bits) {
  606. case 1:
  607. reg_uart.umr2 |= MCF_UART_UMR_SB_STOP_BITS_1;
  608. break;
  609. case 2:
  610. reg_uart.umr2 |= MCF_UART_UMR_SB_STOP_BITS_2;
  611. break;
  612. case 15:
  613. reg_uart.umr2 |= MCF_UART_UMR_SB_STOP_BITS_15;
  614. break;
  615. }
  616. Mcf5UsartDisable();
  617. MCF_UART_UMR(BASE) = reg_uart.umr2;
  618. Mcf5UsartEnable();
  619. /*
  620. * Verify the result.
  621. */
  622. if (Mcf5UsartGetStopBits() != bits) {
  623. return -1;
  624. }
  625. return 0;
  626. }
  627. /*!
  628. * \brief Query the USART hardware status.
  629. *
  630. * \return Status flags.
  631. */
  632. static uint32_t Mcf5UsartGetStatus(void)
  633. {
  634. uint32_t rc = 0;
  635. /*
  636. * Set receiver error flags.
  637. */
  638. if (rx_errors & MCF_UART_USR_FE) {
  639. rc |= UART_FRAMINGERROR;
  640. }
  641. if (rx_errors & MCF_UART_USR_OE) {
  642. rc |= UART_OVERRUNERROR;
  643. }
  644. if (rx_errors & MCF_UART_USR_PE) {
  645. rc |= UART_PARITYERROR;
  646. }
  647. #ifdef XONXOFF
  648. /*
  649. * Determine software handshake status. The flow control status may
  650. * change during interrupt, but this doesn't really hurt us.
  651. */
  652. if (flow_control) {
  653. if (flow_control & XOFF_SENT) {
  654. rc |= UART_RXDISABLED;
  655. }
  656. if (flow_control & XOFF_RCVD) {
  657. rc |= UART_TXDISABLED;
  658. }
  659. }
  660. #endif
  661. #ifdef RTS_PIN
  662. /*
  663. * Determine hardware handshake control status.
  664. */
  665. if (GpioPinGet(RTS_PORT, RTS_PIN)) {
  666. rc |= UART_RTSDISABLED;
  667. if (rts_control) {
  668. rc |= UART_RXDISABLED;
  669. }
  670. } else {
  671. rc |= UART_RTSENABLED;
  672. }
  673. #endif
  674. #ifdef CTS_PIN
  675. /*
  676. * Determine hardware handshake sense status.
  677. */
  678. if (MCF_UART_UIP(BASE) & MCF_UART_UIP_CTS) {
  679. rc |= UART_CTSDISABLED;
  680. if (cts_sense) {
  681. rc |= UART_RXDISABLED;
  682. }
  683. } else {
  684. rc |= UART_CTSENABLED;
  685. }
  686. #endif
  687. /*
  688. * If transmitter and receiver haven't been detected disabled by any
  689. * of the checks above, then they are probably enabled.
  690. */
  691. if ((rc & UART_RXDISABLED) == 0) {
  692. rc |= UART_RXENABLED;
  693. }
  694. if ((rc & UART_TXDISABLED) == 0) {
  695. rc |= UART_TXENABLED;
  696. }
  697. return rc;
  698. }
  699. /*!
  700. * \brief Set the USART hardware status.
  701. *
  702. * \param flags Status flags.
  703. *
  704. * \return 0 on success, -1 otherwise.
  705. */
  706. static int Mcf5UsartSetStatus(uint32_t flags)
  707. {
  708. /*
  709. * Clear UART receive errors.
  710. */
  711. if (flags & UART_FRAMINGERROR) {
  712. rx_errors &= ~MCF_UART_USR_FE;
  713. }
  714. if (flags & UART_OVERRUNERROR) {
  715. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_ERROR;
  716. rx_errors &= ~MCF_UART_USR_OE;
  717. }
  718. if (flags & UART_PARITYERROR) {
  719. rx_errors &= ~MCF_UART_USR_PE;
  720. }
  721. #ifdef XONXOFF
  722. /*
  723. * Process software handshake control.
  724. */
  725. if (flow_control) {
  726. /* Access to the flow control status must be atomic. */
  727. NutEnterCritical();
  728. /*
  729. * Enabling or disabling the receiver means to behave like
  730. * having sent a XON or XOFF character resp.
  731. */
  732. if (flags & UART_RXENABLED) {
  733. flow_control &= ~XOFF_SENT;
  734. } else if (flags & UART_RXDISABLED) {
  735. flow_control |= XOFF_SENT;
  736. }
  737. /*
  738. * Enabling or disabling the transmitter means to behave like
  739. * having received a XON or XOFF character resp.
  740. */
  741. if (flags & UART_TXENABLED) {
  742. flow_control &= ~XOFF_RCVD;
  743. } else if (flags & UART_TXDISABLED) {
  744. flow_control |= XOFF_RCVD;
  745. }
  746. NutExitCritical();
  747. }
  748. #endif
  749. /*
  750. * Read only or not supported flags
  751. */
  752. if (flags & (
  753. #ifndef XONXOFF
  754. UART_RXENABLED | UART_RXDISABLED | UART_TXENABLED | UART_TXDISABLED |
  755. #endif
  756. UART_RTSENABLED | UART_RTSDISABLED | UART_CTSENABLED | UART_CTSDISABLED |
  757. UART_RXADDRFRAME | UART_RXNORMFRAME | UART_TXADDRFRAME | UART_TXNORMFRAME |
  758. UART_DTRENABLED | UART_DTRDISABLED ))
  759. return -1;
  760. return 0;
  761. }
  762. /*!
  763. * \brief Query flow control mode.
  764. *
  765. * This routine is called by ioctl function of the upper level USART
  766. * driver through the USARTDCB jump table.
  767. *
  768. * \return See UsartIOCtl().
  769. */
  770. static uint32_t Mcf5UsartGetFlowControl(void)
  771. {
  772. uint32_t rc = 0;
  773. #ifdef XONXOFF
  774. if (flow_control) {
  775. rc |= USART_MF_XONXOFF;
  776. } else {
  777. rc &= ~USART_MF_XONXOFF;
  778. }
  779. #endif
  780. #ifdef RTS_PIN
  781. if (rts_control) {
  782. rc |= USART_MF_RTSCONTROL;
  783. } else {
  784. rc &= ~USART_MF_RTSCONTROL;
  785. }
  786. #endif
  787. #ifdef CTS_PIN
  788. if (cts_sense) {
  789. rc |= USART_MF_CTSSENSE;
  790. } else {
  791. rc &= ~USART_MF_CTSSENSE;
  792. }
  793. #endif
  794. if (hdx_control) {
  795. rc |= USART_MF_HALFDUPLEX;
  796. } else {
  797. rc &= ~USART_MF_HALFDUPLEX;
  798. }
  799. return rc;
  800. }
  801. /*!
  802. * \brief Set flow control mode.
  803. *
  804. * This function is called by ioctl function of the upper level USART
  805. * driver through the USARTDCB jump table.
  806. * Nove pridan parametr USART_MF_HALFDUPLEX_YZ, ktery se vklada spolecne
  807. * s parametrem USART_MF_HALFDUPLEX. Pokud USART_MF_HALFDUPLEX_YZ je
  808. * zadan komonikuje se pres porty XY, pokud neni tak pres AB.
  809. *
  810. * \param flags See UsartIOCtl().
  811. *
  812. * \return 0 on success, -1 otherwise.
  813. */
  814. static int Mcf5UsartSetFlowControl(uint32_t flags)
  815. {
  816. #ifdef XONXOFF
  817. /*
  818. * Set software handshake mode.
  819. */
  820. if (flags & USART_MF_XONXOFF) {
  821. if(!flow_control) {
  822. NutEnterCritical();
  823. flow_control = 1 | XOFF_SENT; /* force XON to be sent on next read */
  824. NutExitCritical();
  825. }
  826. } else if (flow_control){
  827. NutEnterCritical();
  828. flow_control = 0;
  829. NutExitCritical();
  830. }
  831. #endif
  832. #ifdef RTS_PIN
  833. /*
  834. * Set hardware RTS control mode.
  835. */
  836. if (flags & USART_MF_RTSCONTROL) {
  837. rts_control = 1;
  838. reg_uart.umr1 |= MCF_UART_UMR_RXRTS;
  839. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_MR;
  840. MCF_UART_UMR(BASE) = reg_uart.umr1;
  841. } else {
  842. rts_control = 0;
  843. reg_uart.umr1 &= ~MCF_UART_UMR_RXRTS;
  844. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_MR;
  845. MCF_UART_UMR(BASE) = reg_uart.umr1;
  846. }
  847. #endif
  848. #ifdef CTS_PIN
  849. /*
  850. * Set hardware CTS sense mode.
  851. */
  852. if (flags & USART_MF_CTSSENSE) {
  853. cts_sense = 1;
  854. reg_uart.umr2 |= MCF_UART_UMR_TXCTS;
  855. MCF_UART_UMR(BASE) = reg_uart.umr2;
  856. } else {
  857. cts_sense = 0;
  858. reg_uart.umr2 &= ~MCF_UART_UMR_TXCTS;
  859. MCF_UART_UMR(BASE) = reg_uart.umr2;
  860. }
  861. #endif
  862. /*
  863. * Set duplex mode.
  864. */
  865. if (flags & USART_MF_HALFDUPLEX) {
  866. hdx_control = 1;
  867. /* Switch RS485 bus driver to half duplex */
  868. HDX_CTRL_HALF();
  869. } else {
  870. hdx_control = 0;
  871. /* Switch RS485 bus driver to receive/transmit mode */
  872. HDX_CTRL_FULL();
  873. RS485_CTRL_RX_ENA();
  874. RS485_CTRL_TX_ENA();
  875. /* Enable receiver */
  876. MCF_UART_UCR(BASE) = MCF_UART_UCR_RX_ENABLED;
  877. }
  878. /*
  879. * Verify the result.
  880. */
  881. if (Mcf5UsartGetFlowControl() != flags) {
  882. return -1;
  883. }
  884. return 0;
  885. }
  886. /*!
  887. * \brief Start the USART transmitter hardware.
  888. *
  889. * The upper level USART driver will call this function through the
  890. * USARTDCB jump table each time it added one or more bytes to the
  891. * transmit buffer.
  892. */
  893. static void Mcf5UsartTxStart(void)
  894. {
  895. if (hdx_control) {
  896. /*
  897. * Disable receiver in half-duplex mode
  898. */
  899. MCF_UART_UCR(BASE) = MCF_UART_UCR_RX_DISABLED;
  900. /*
  901. * Switch RS485 bus driver to transmit mode
  902. */
  903. RS485_CTRL_RX_DIS();
  904. RS485_CTRL_TX_ENA();
  905. }
  906. /* Enable Transmit Ready Interrupt */
  907. SET_TXRDY_INTERRUPT();
  908. }
  909. /*!
  910. * \brief Start the USART receiver hardware.
  911. *
  912. * The upper level USART driver will call this function through the
  913. * USARTDCB jump table each time it removed enough bytes from the
  914. * receive buffer. Enough means, that the number of bytes left in
  915. * the buffer is below the low watermark.
  916. */
  917. static void Mcf5UsartRxStart(void)
  918. {
  919. #ifdef XONXOFF
  920. /*
  921. * Do any required software flow control.
  922. */
  923. if (flow_control && (flow_control & XOFF_SENT)) {
  924. NutEnterCritical();
  925. if (MCF_UART_USR(BASE) & MCF_UART_USR_TXRDY) {
  926. MCF_UART_UTB(BASE) = ASCII_XON;
  927. flow_control &= ~XON_PENDING;
  928. } else {
  929. flow_control |= XON_PENDING;
  930. }
  931. flow_control &= ~(XOFF_SENT | XOFF_PENDING);
  932. NutExitCritical();
  933. }
  934. #endif
  935. /*
  936. * Enable receive interrupt. It could be disabled by flow control.
  937. */
  938. SET_RXRDY_INTERRUPT();
  939. }
  940. /*
  941. * \brief Initialize the USART hardware driver.
  942. *
  943. * This function is called during device registration by the upper level
  944. * USART driver through the USARTDCB jump table.
  945. *
  946. * \return 0 on success, -1 otherwise.
  947. */
  948. static int Mcf5UsartInit(void)
  949. {
  950. int result = 0;
  951. /*
  952. * Disable UART's interrupts
  953. */
  954. CLR_ALL_INTERRUPT();
  955. /*
  956. * UART Reset
  957. */
  958. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_TX;
  959. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_RX;
  960. MCF_UART_UCR(BASE) = MCF_UART_UCR_RESET_MR;
  961. /*
  962. * Initialize UART's write only registers
  963. */
  964. memset(&reg_uart, 0, sizeof(reg_uart));
  965. /*
  966. * GPIO Configuration
  967. */
  968. result |= GpioPinConfigSet(RXD_PORT, RXD_PIN, RXD_PERIPHERAL);
  969. result |= GpioPinConfigSet(TXD_PORT, TXD_PIN, TXD_PERIPHERAL);
  970. #ifdef RTS_PIN
  971. result |= GpioPinConfigSet(RTS_PORT, RTS_PIN, RTS_PERIPHERAL);
  972. #endif
  973. #ifdef CTS_PIN
  974. result |= GpioPinConfigSet(CTS_PORT, CTS_PIN, CTS_PERIPHERAL);
  975. #endif
  976. #ifdef HDX_CTRL_PIN
  977. result |= GpioPinConfigSet(HDX_CTRL_PORT, HDX_CTRL_PIN, GPIO_CFG_OUTPUT);
  978. #endif
  979. #ifdef RS485_CTRL_DE_PIN
  980. result |= GpioPinConfigSet(RS485_CTRL_DE_PORT, RS485_CTRL_DE_PIN, GPIO_CFG_OUTPUT);
  981. #endif
  982. #ifdef RS485_CTRL_RE_PIN
  983. result |= GpioPinConfigSet(RS485_CTRL_RE_PORT, RS485_CTRL_RE_PIN, GPIO_CFG_OUTPUT);
  984. #endif
  985. /*
  986. * Use internal bus clock as the clock source for Rx and Tx
  987. */
  988. MCF_UART_UCSR(BASE) = MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK;
  989. /*
  990. * UART Configuration
  991. */
  992. result |= Mcf5UsartSetFlowControl(0
  993. #ifdef HDX_ENABLED
  994. | USART_MF_HALFDUPLEX
  995. #endif
  996. );
  997. result |= Mcf5UsartSetDataBits(8);
  998. result |= Mcf5UsartSetStopBits(1);
  999. result |= Mcf5UsartSetParity(0);
  1000. result |= Mcf5UsartSetSpeed(USART_INITSPEED);
  1001. /*
  1002. * Trigger interrupt when /CTS has change of state
  1003. */
  1004. MCF_UART_UACR(BASE) = MCF_UART_UACR_IEC;
  1005. /*
  1006. * Disable UART's interrupts
  1007. */
  1008. CLR_ALL_INTERRUPT();
  1009. /*
  1010. * Register and enable Interrupt handler
  1011. */
  1012. if (result
  1013. || NutRegisterIrqHandler(&sig_uart, Mcf5UsartInterrupts, &dcb_uart)
  1014. || NutIrqEnable(&sig_uart))
  1015. return -1;
  1016. /*
  1017. * Start receiving immediatelly
  1018. * NOTE: Transmitting is started too, but it is stopped after while in Mcf5UsartTxReady()
  1019. */
  1020. Mcf5UsartEnable();
  1021. return 0;
  1022. }
  1023. /*
  1024. * \brief Deinitialize the USART hardware driver.
  1025. *
  1026. * This function is called during device deregistration by the upper
  1027. * level USART driver through the USARTDCB jump table.
  1028. *
  1029. * \return 0 on success, -1 otherwise.
  1030. */
  1031. static int Mcf5UsartDeinit(void)
  1032. {
  1033. /* Deregister receive and transmit interrupts. */
  1034. NutIrqDisable(&sig_uart);
  1035. /* Deregister receive and transmit interrupts. */
  1036. NutRegisterIrqHandler(&sig_uart, 0, 0);
  1037. return 0;
  1038. }
  1039. /*@}*/