uartgba.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00033 /*
00034  * $Log: uartgba.c,v $
00035  * Revision 1.4  2007/08/29 07:43:52  haraldkipp
00036  * Documentation updated and corrected.
00037  *
00038  * Revision 1.3  2005/10/24 17:59:19  haraldkipp
00039  * Use correct header file, arm, not gba.
00040  *
00041  * Revision 1.2  2005/08/02 17:46:45  haraldkipp
00042  * Major API documentation update.
00043  *
00044  * Revision 1.1  2005/07/26 18:02:26  haraldkipp
00045  * Moved from dev.
00046  *
00047  * Revision 1.1  2005/04/05 18:01:43  haraldkipp
00048  * This code is buggy! Anyone willing to help?
00049  *
00050  */
00051 
00052 #include <sys/atom.h>
00053 #include <sys/event.h>
00054 #include <sys/timer.h>
00055 
00056 #include <dev/irqreg.h>
00057 
00058 #include <arch/arm.h>
00059 #include <dev/usart.h>
00060 
00061 #include <stdio.h>
00066 
00067 /* \brief ASCII code for software flow control, starts transmitter. */
00068 #define ASCII_XON   0x11
00069 /* \brief ASCII code for software flow control, stops transmitter. */
00070 #define ASCII_XOFF  0x13
00071 
00072 /* \brief XON transmit pending flag. */
00073 #define XON_PENDING     0x10
00074 /* \brief XOFF transmit pending flag. */
00075 #define XOFF_PENDING    0x20
00076 /* \brief XOFF sent flag. */
00077 #define XOFF_SENT       0x40
00078 /* \brief XOFF received flag. */
00079 #define XOFF_RCVD       0x80
00080 
00081 
00085 //static ureg_t rx_errors;
00086 
00090 static ureg_t flow_control;
00091 
00092 static volatile ureg_t tx_stop = 1;
00093 
00094 static USARTDCB dcb_uart;
00095 
00096 /*
00097  * \brief USART0 transmit data register empty interrupt handler.
00098  *
00099  * \param arg Pointer to the transmitter ring buffer.
00100  */
00101 static void GbaUartTxEmpty(RINGBUF * rbf)
00102 {
00103     register u_char *cp = rbf->rbf_tail;
00104 
00105     /*
00106      * Process pending software flow controls first.
00107      */
00108     if (flow_control & (XON_PENDING | XOFF_PENDING)) {
00109         if (flow_control & XON_PENDING) {
00110             outw(REG_SIODATA8, ASCII_XOFF);
00111             flow_control |= XOFF_SENT;
00112         } else {
00113             outw(REG_SIODATA8, ASCII_XON);
00114             flow_control &= ~XOFF_SENT;
00115         }
00116         flow_control &= ~(XON_PENDING | XOFF_PENDING);
00117         return;
00118     }
00119 
00120     if (flow_control & XOFF_RCVD) {
00121         /* 
00122          * If XOFF has been received, we disable the transmit interrupts
00123          * and return without sending anything.
00124          */
00125         tx_stop = 1;
00126         outw(REG_SIOCNT, inw(REG_SIOCNT) & ~SIO_SEND_ENA);
00127         return;
00128     }
00129 
00130     if (rbf->rbf_cnt) {
00131 
00132         rbf->rbf_cnt--;
00133 
00134         /*
00135          * Start transmission of the next character.
00136          */
00137         outw(REG_SIODATA8, *cp);
00138 
00139         /*
00140          * Wrap around the buffer pointer if we reached its end.
00141          */
00142         if (++cp == rbf->rbf_last) {
00143             cp = rbf->rbf_start;
00144         }
00145         rbf->rbf_tail = cp;
00146         if (rbf->rbf_cnt == rbf->rbf_lwm) {
00147             NutEventPostFromIrq(&rbf->rbf_que);
00148         }
00149     }
00150 
00151     /*
00152      * Nothing left to transmit, disable interrupt.
00153      */
00154     else {
00155         tx_stop = 1;
00156         outw(REG_SIOCNT, (inw(REG_SIOCNT) & ~SIO_SEND_ENA) | SIO_TX_FULL);
00157         rbf->rbf_cnt = 0;
00158         NutEventPostFromIrq(&rbf->rbf_que);
00159     }
00160 }
00161 
00162 /*
00163  * \brief USART0 receive complete interrupt handler.
00164  *
00165  *
00166  * \param arg Pointer to the receiver ring buffer.
00167  */
00168 static void GbaUartRxFull(RINGBUF * rbf)
00169 {
00170     register size_t cnt;
00171     register u_char ch;
00172 
00173     /*
00174      * We read the received character as early as possible to avoid overflows
00175      * caused by interrupt latency. However, reading the error flags must come 
00176      * first, because reading the ATmega128 data register clears the status.
00177      */
00178     //TODO rx_errors |= inb(UCSRnA);
00179     ch = (u_char) inw(REG_SIODATA8);
00180 
00181     /*
00182      * Handle software handshake. We have to do this before checking the
00183      * buffer, because flow control must work in write-only mode, where
00184      * there is no receive buffer.
00185      */
00186     if (flow_control) {
00187         /* XOFF character disables transmit interrupts. */
00188         if (ch == ASCII_XOFF) {
00189             tx_stop = 1;
00190             outw(REG_SIOCNT, inw(REG_SIOCNT) & ~SIO_SEND_ENA);
00191             flow_control |= XOFF_RCVD;
00192             return;
00193         }
00194         /* XON enables transmit interrupts. */
00195         else if (ch == ASCII_XON) {
00196             tx_stop = 0; //TODO
00197             outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_SEND_ENA);
00198             flow_control &= ~XOFF_RCVD;
00199             return;
00200         }
00201     }
00202 
00203     /*
00204      * Check buffer overflow.
00205      */
00206     cnt = rbf->rbf_cnt;
00207     if (cnt >= rbf->rbf_siz) {
00208         //TODO rx_errors |= _BV(DOR);
00209         return;
00210     }
00211 
00212     /* Wake up waiting threads if this is the first byte in the buffer. */
00213     if (cnt++ == 0) {
00214         NutEventPostFromIrq(&rbf->rbf_que);
00215     }
00216 
00217     /*
00218      * Check the high watermark for software handshake. If the number of 
00219      * buffered bytes is above this mark, then send XOFF.
00220      */
00221     else if (flow_control) {
00222         if (cnt >= rbf->rbf_hwm) {
00223             if ((flow_control & XOFF_SENT) == 0) {
00224                 if (inw(REG_SIOCNT) & SIO_TX_FULL) {
00225                     flow_control |= XOFF_PENDING;
00226                 } else {
00227                     outw(REG_SIODATA8, ASCII_XOFF);
00228                     flow_control |= XOFF_SENT;
00229                     flow_control &= ~XOFF_PENDING;
00230                 }
00231             }
00232         }
00233     }
00234 
00235     /* 
00236      * Store the character and increment and the ring buffer pointer. 
00237      */
00238     *rbf->rbf_head++ = ch;
00239     if (rbf->rbf_head == rbf->rbf_last) {
00240         rbf->rbf_head = rbf->rbf_start;
00241     }
00242 
00243     /* Update the ring buffer counter. */
00244     rbf->rbf_cnt = cnt;
00245 }
00246 
00247 static void GbaUartIsr(void *arg)
00248 {
00249     /* Clear interrupt. */
00250     outw(REG_IF, INT_SIO);
00251 
00252     if ((inw(REG_SIOCNT) & SIO_RX_EMPTY) == 0) {
00253         GbaUartRxFull(&((USARTDCB *) arg)->dcb_rx_rbf);
00254     }
00255     if ((inw(REG_SIOCNT) & SIO_TX_FULL) == 0) {
00256         GbaUartTxEmpty(&((USARTDCB *) arg)->dcb_tx_rbf);
00257     }
00258 }
00259 
00266 static void GbaUartEnable(void)
00267 {
00268     NutEnterCritical();
00269 
00270     //TODO outb(UCSRnB, _BV(RXCIE) | _BV(UDRIE) | _BV(RXEN) | _BV(TXEN));
00271 
00272     NutExitCritical();
00273 }
00274 
00278 static void GbaUartDisable(void)
00279 {
00280     /*
00281      * Disable USART interrupts.
00282      */
00283     //TODO NutEnterCritical();
00284     //TODO cbi(UCSRnB, RXCIE);
00285     //TODO cbi(UCSRnB, TXCIE);
00286     //TODO cbi(UCSRnB, UDRIE);
00287     //TODO NutExitCritical();
00288 
00289     /*
00290      * Allow incoming or outgoing character to finish.
00291      */
00292     //TODO NutDelay(10);
00293 
00294     /*
00295      * Disable USART transmit and receive.
00296      */
00297     //TODO cbi(UCSRnB, RXEN);
00298     //TODO cbi(UCSRnB, TXEN);
00299 }
00300 
00309 static u_long GbaUartGetSpeed(void)
00310 {
00311     u_short sv = inw(REG_SIOCNT);
00312 
00313     if ((sv & SIO_BAUD_115200) == SIO_BAUD_115200) {
00314         return 115200UL;
00315     }
00316     if ((sv & SIO_BAUD_57600) == SIO_BAUD_57600) {
00317         return 57600UL;
00318     }
00319     if ((sv & SIO_BAUD_38400) == SIO_BAUD_38400) {
00320         return 38400L;
00321     }
00322     return 9600UL;
00323 }
00324 
00335 static int GbaUartSetSpeed(u_long rate)
00336 {
00337     u_short sv;
00338 
00339     GbaUartDisable();
00340     sv = inw(REG_SIOCNT) & ~SIO_BAUD_115200;
00341     if (rate == 115200) {
00342         sv |= SIO_BAUD_115200;
00343     } else {
00344         if (rate == 57600) {
00345             sv |= SIO_BAUD_57600;
00346         } else if (rate == 38400) {
00347             sv |= SIO_BAUD_38400;
00348         }
00349     }
00350     outw(REG_SIOCNT, sv);
00351     GbaUartEnable();
00352 
00353     return 0;
00354 }
00355 
00364 static u_char GbaUartGetDataBits(void)
00365 {
00366     return 8;
00367 }
00368 
00377 static int GbaUartSetDataBits(u_char bits)
00378 {
00379     GbaUartDisable();
00380     GbaUartEnable();
00381 
00382     /*
00383      * Verify the result.
00384      */
00385     if (GbaUartGetDataBits() != bits) {
00386         return -1;
00387     }
00388     return 0;
00389 }
00390 
00399 static u_char GbaUartGetParity(void)
00400 {
00401     return 0;
00402 }
00403 
00414 static int GbaUartSetParity(u_char mode)
00415 {
00416     GbaUartDisable();
00417     GbaUartEnable();
00418 
00419     /*
00420      * Verify the result.
00421      */
00422     if (GbaUartGetParity() != mode) {
00423         return -1;
00424     }
00425     return 0;
00426 }
00427 
00436 static u_char GbaUartGetStopBits(void)
00437 {
00438     return 1;
00439 }
00440 
00449 static int GbaUartSetStopBits(u_char bits)
00450 {
00451     GbaUartDisable();
00452     GbaUartEnable();
00453 
00454     /*
00455      * Verify the result.
00456      */
00457     if (GbaUartGetStopBits() != bits) {
00458         return -1;
00459     }
00460     return 0;
00461 }
00462 
00468 static u_long GbaUartGetStatus(void)
00469 {
00470     u_long rc = 0;
00471 
00472     /*
00473      * Set receiver error flags.
00474      */
00475 
00476     /*
00477      * Determine software handshake status. The flow control status may
00478      * change during interrupt, but this doesn't really hurt us.
00479      */
00480     if (flow_control) {
00481         if (flow_control & XOFF_SENT) {
00482             rc |= UART_RXDISABLED;
00483         }
00484         if (flow_control & XOFF_RCVD) {
00485             rc |= UART_TXDISABLED;
00486         }
00487     }
00488 
00489     /*
00490      * If transmitter and receiver haven't been detected disabled by any
00491      * of the checks above, then they are probably enabled.
00492      */
00493     if ((rc & UART_RXDISABLED) == 0) {
00494         rc |= UART_RXENABLED;
00495     }
00496     if ((rc & UART_TXDISABLED) == 0) {
00497         rc |= UART_TXENABLED;
00498     }
00499     return rc;
00500 }
00501 
00509 static int GbaUartSetStatus(u_long flags)
00510 {
00511     /*
00512      * Process software handshake control.
00513      */
00514     if (flow_control) {
00515 
00516         /* Access to the flow control status must be atomic. */
00517         NutEnterCritical();
00518 
00519         /*
00520          * Enabling or disabling the receiver means to behave like 
00521          * having sent a XON or XOFF character resp.
00522          */
00523         if (flags & UART_RXENABLED) {
00524             flow_control &= ~XOFF_SENT;
00525         } else if (flags & UART_RXDISABLED) {
00526             flow_control |= XOFF_SENT;
00527         }
00528 
00529         /*
00530          * Enabling or disabling the transmitter means to behave like 
00531          * having received a XON or XOFF character resp.
00532          */
00533         if (flags & UART_TXENABLED) {
00534             flow_control &= ~XOFF_RCVD;
00535         } else if (flags & UART_TXDISABLED) {
00536             flow_control |= XOFF_RCVD;
00537         }
00538         NutExitCritical();
00539     }
00540 
00541     /*
00542      * Verify the result.
00543      */
00544     if ((GbaUartGetStatus() & ~UART_ERRORS) != flags) {
00545         return -1;
00546     }
00547     return 0;
00548 }
00549 
00559 static u_char GbaUartGetClockMode(void)
00560 {
00561     return 0;
00562 }
00563 
00575 static int GbaUartSetClockMode(u_char mode)
00576 {
00577     /*
00578      * Verify the result.
00579      */
00580     if (GbaUartGetClockMode() != mode) {
00581         return -1;
00582     }
00583     return 0;
00584 }
00585 
00594 static u_long GbaUartGetFlowControl(void)
00595 {
00596     u_long rc = 0;
00597 
00598     if (flow_control) {
00599         rc |= USART_MF_XONXOFF;
00600     } else {
00601         rc &= ~USART_MF_XONXOFF;
00602     }
00603 
00604     return rc;
00605 }
00606 
00617 static int GbaUartSetFlowControl(u_long flags)
00618 {
00619     /*
00620      * Set software handshake mode.
00621      */
00622     if (flags & USART_MF_XONXOFF) {
00623         if (flow_control == 0) {
00624             NutEnterCritical();
00625             flow_control = 1 | XOFF_SENT;       /* force XON to be sent on next read */
00626             NutExitCritical();
00627         }
00628     } else {
00629         NutEnterCritical();
00630         flow_control = 0;
00631         NutExitCritical();
00632     }
00633 
00634     /*
00635      * Verify the result.
00636      */
00637     if (GbaUartGetFlowControl() != flags) {
00638         return -1;
00639     }
00640     return 0;
00641 }
00642 
00650 static void GbaUartTxStart(void)
00651 {
00652     RINGBUF *rbf = &dcb_uart.dcb_tx_rbf;
00653     register u_char *cp = rbf->rbf_tail;
00654 
00655     NutEnterCritical();
00656     if(tx_stop) {
00657         if (rbf->rbf_cnt) {
00658             rbf->rbf_cnt--;
00659             outw(REG_SIODATA8, *cp);
00660             if (++cp == rbf->rbf_last) {
00661                 cp = rbf->rbf_start;
00662             }
00663             rbf->rbf_tail = cp;
00664             tx_stop = 0;
00665         }
00666     }
00667     outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_SEND_ENA);
00668     NutExitCritical();
00669 }
00670 
00679 static void GbaUartRxStart(void)
00680 {
00681     /*
00682      * Do any required software flow control.
00683      */
00684     NutEnterCritical();
00685     if (flow_control && (flow_control & XOFF_SENT) != 0) {
00686         if (inw(REG_SIOCNT) & SIO_TX_FULL) {
00687             flow_control |= XON_PENDING;
00688         } else {
00689             outw(REG_SIODATA8, ASCII_XON);
00690             flow_control &= ~XON_PENDING;
00691         }
00692         flow_control &= ~(XOFF_SENT | XOFF_PENDING);
00693     }
00694     outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_RECV_ENA);
00695     NutExitCritical();
00696 }
00697 
00698 /*
00699  * \brief Initialize the USART hardware driver.
00700  *
00701  * This function is called during device registration by the upper level 
00702  * USART driver through the USARTDCB jump table.
00703  *
00704  * \return 0 on success, -1 otherwise.
00705  */
00706 static int GbaUartInit(void)
00707 {
00708     int rc;
00709 
00710     /*
00711      * Activate MBV2 UART mode by setting SC low and SD high for at 
00712      * least 50 milliseconds.
00713      */
00714     outw(REG_RCNT, 0x8032);
00715     NutSleep(100);
00716 
00717     /* Disable master interrupt. */
00718     outw(REG_IME, 0);
00719 
00720     /* Register our interrupt service. */
00721     if((rc = NutRegisterIrqHandler(&sig_SIO, GbaUartIsr, &dcb_uart)) == 0) {
00722 
00723         /* Enable UART mode. */
00724         outw(REG_RCNT, 0x0000);
00725 
00726         /* Set UART mode */
00727         outw(REG_SIOCNT, SIO_IRQ_ENA | SIO_MODE_UART | SIO_DATA_8BIT | SIO_BAUD_38400);
00728 
00729         /* Clear receive/transmit */
00730         outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_RX_EMPTY | SIO_TX_FULL);
00731 
00732         /* Enable FIFO. */
00733         //outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_FIFO_ENA);
00734 
00735         /* Enable SIO interrupts. */
00736         outw(REG_IE, inw(REG_IE) | INT_SIO);
00737     }
00738 
00739     printf("I[%04X]", inw(REG_SIOCNT));
00740 
00741     /* Enable master interrupt. */
00742     outw(REG_IME, 1);
00743 
00744     return rc;
00745 }
00746 
00747 /*
00748  * \brief Deinitialize the USART hardware driver.
00749  *
00750  * This function is called during device deregistration by the upper 
00751  * level USART driver through the USARTDCB jump table.
00752  *
00753  * \return 0 on success, -1 otherwise.
00754  */
00755 static int GbaUartDeinit(void)
00756 {
00757     /* Deregister receive and transmit interrupts. */
00758     NutRegisterIrqHandler(&sig_SIO, 0, 0);
00759 
00760     return 0;
00761 }
00762 
00763 #if 1
00764 
00767 static USARTDCB dcb_uart = {
00768     0,                          /* dcb_modeflags */
00769     0,                          /* dcb_statusflags */
00770     0,                          /* dcb_rtimeout */
00771     0,                          /* dcb_wtimeout */
00772     {0, 0, 0, 0, 0, 0, 0, 0},   /* dcb_tx_rbf */
00773     {0, 0, 0, 0, 0, 0, 0, 0},   /* dcb_rx_rbf */
00774     0,                          /* dbc_last_eol */
00775     GbaUartInit,                /* dcb_init */
00776     GbaUartDeinit,              /* dcb_deinit */
00777     GbaUartTxStart,             /* dcb_tx_start */
00778     GbaUartRxStart,             /* dcb_rx_start */
00779     GbaUartSetFlowControl,      /* dcb_set_flow_control */
00780     GbaUartGetFlowControl,      /* dcb_get_flow_control */
00781     GbaUartSetSpeed,            /* dcb_set_speed */
00782     GbaUartGetSpeed,            /* dcb_get_speed */
00783     GbaUartSetDataBits,         /* dcb_set_data_bits */
00784     GbaUartGetDataBits,         /* dcb_get_data_bits */
00785     GbaUartSetParity,           /* dcb_set_parity */
00786     GbaUartGetParity,           /* dcb_get_parity */
00787     GbaUartSetStopBits,         /* dcb_set_stop_bits */
00788     GbaUartGetStopBits,         /* dcb_get_stop_bits */
00789     GbaUartSetStatus,           /* dcb_set_status */
00790     GbaUartGetStatus,           /* dcb_get_status */
00791     GbaUartSetClockMode,        /* dcb_set_clock_mode */
00792     GbaUartGetClockMode,        /* dcb_get_clock_mode */
00793 };
00794 
00810 NUTDEVICE devUartGba = {
00811     0,                          /* Pointer to next device, dev_next. */
00812     {'u', 'a', 'r', 't', '0', 0, 0, 0, 0},      /* Unique device name, dev_name. */
00813     IFTYP_CHAR,                 /* Type of device, dev_type. */
00814     0,                          /* Base address, dev_base (not used). */
00815     0,                          /* First interrupt number, dev_irq (not used). */
00816     0,                          /* Interface control block, dev_icb (not used). */
00817     &dcb_uart,                  /* Driver control block, dev_dcb. */
00818     UsartInit,                  /* Driver initialization routine, dev_init. */
00819     UsartIOCtl,                 /* Driver specific control function, dev_ioctl. */
00820     UsartRead,                  /* Read from device, dev_read. */
00821     UsartWrite,                 /* Write to device, dev_write. */
00822     UsartOpen,                  /* Open a device or file, dev_open. */
00823     UsartClose,                 /* Close a device or file, dev_close. */
00824     UsartSize                   /* Request file size, dev_size. */
00825 };
00826 #endif
00827 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/