Nut/OS  4.10.3
API Reference
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$
00035  * Revision 1.5  2008/08/11 06:59:13  haraldkipp
00036  * BSD types replaced by stdint types (feature request #1282721).
00037  *
00038  * Revision 1.4  2007/08/29 07:43:52  haraldkipp
00039  * Documentation updated and corrected.
00040  *
00041  * Revision 1.3  2005/10/24 17:59:19  haraldkipp
00042  * Use correct header file, arm, not gba.
00043  *
00044  * Revision 1.2  2005/08/02 17:46:45  haraldkipp
00045  * Major API documentation update.
00046  *
00047  * Revision 1.1  2005/07/26 18:02:26  haraldkipp
00048  * Moved from dev.
00049  *
00050  * Revision 1.1  2005/04/05 18:01:43  haraldkipp
00051  * This code is buggy! Anyone willing to help?
00052  *
00053  */
00054 
00055 #include <sys/atom.h>
00056 #include <sys/event.h>
00057 #include <sys/timer.h>
00058 
00059 #include <dev/irqreg.h>
00060 
00061 #include <arch/arm.h>
00062 #include <dev/usart.h>
00063 
00064 #include <stdio.h>
00069 
00070 /* \brief ASCII code for software flow control, starts transmitter. */
00071 #define ASCII_XON   0x11
00072 /* \brief ASCII code for software flow control, stops transmitter. */
00073 #define ASCII_XOFF  0x13
00074 
00075 /* \brief XON transmit pending flag. */
00076 #define XON_PENDING     0x10
00077 /* \brief XOFF transmit pending flag. */
00078 #define XOFF_PENDING    0x20
00079 /* \brief XOFF sent flag. */
00080 #define XOFF_SENT       0x40
00081 /* \brief XOFF received flag. */
00082 #define XOFF_RCVD       0x80
00083 
00084 
00088 //static ureg_t rx_errors;
00089 
00093 static ureg_t flow_control;
00094 
00095 static volatile ureg_t tx_stop = 1;
00096 
00097 static USARTDCB dcb_uart;
00098 
00099 /*
00100  * \brief USART0 transmit data register empty interrupt handler.
00101  *
00102  * \param arg Pointer to the transmitter ring buffer.
00103  */
00104 static void GbaUartTxEmpty(RINGBUF * rbf)
00105 {
00106     register uint8_t *cp = rbf->rbf_tail;
00107 
00108     /*
00109      * Process pending software flow controls first.
00110      */
00111     if (flow_control & (XON_PENDING | XOFF_PENDING)) {
00112         if (flow_control & XON_PENDING) {
00113             outw(REG_SIODATA8, ASCII_XOFF);
00114             flow_control |= XOFF_SENT;
00115         } else {
00116             outw(REG_SIODATA8, ASCII_XON);
00117             flow_control &= ~XOFF_SENT;
00118         }
00119         flow_control &= ~(XON_PENDING | XOFF_PENDING);
00120         return;
00121     }
00122 
00123     if (flow_control & XOFF_RCVD) {
00124         /* 
00125          * If XOFF has been received, we disable the transmit interrupts
00126          * and return without sending anything.
00127          */
00128         tx_stop = 1;
00129         outw(REG_SIOCNT, inw(REG_SIOCNT) & ~SIO_SEND_ENA);
00130         return;
00131     }
00132 
00133     if (rbf->rbf_cnt) {
00134 
00135         rbf->rbf_cnt--;
00136 
00137         /*
00138          * Start transmission of the next character.
00139          */
00140         outw(REG_SIODATA8, *cp);
00141 
00142         /*
00143          * Wrap around the buffer pointer if we reached its end.
00144          */
00145         if (++cp == rbf->rbf_last) {
00146             cp = rbf->rbf_start;
00147         }
00148         rbf->rbf_tail = cp;
00149         if (rbf->rbf_cnt == rbf->rbf_lwm) {
00150             NutEventPostFromIrq(&rbf->rbf_que);
00151         }
00152     }
00153 
00154     /*
00155      * Nothing left to transmit, disable interrupt.
00156      */
00157     else {
00158         tx_stop = 1;
00159         outw(REG_SIOCNT, (inw(REG_SIOCNT) & ~SIO_SEND_ENA) | SIO_TX_FULL);
00160         rbf->rbf_cnt = 0;
00161         NutEventPostFromIrq(&rbf->rbf_que);
00162     }
00163 }
00164 
00165 /*
00166  * \brief USART0 receive complete interrupt handler.
00167  *
00168  *
00169  * \param arg Pointer to the receiver ring buffer.
00170  */
00171 static void GbaUartRxFull(RINGBUF * rbf)
00172 {
00173     register size_t cnt;
00174     register uint8_t ch;
00175 
00176     /*
00177      * We read the received character as early as possible to avoid overflows
00178      * caused by interrupt latency. However, reading the error flags must come 
00179      * first, because reading the ATmega128 data register clears the status.
00180      */
00181     //TODO rx_errors |= inb(UCSRnA);
00182     ch = (uint8_t) inw(REG_SIODATA8);
00183 
00184     /*
00185      * Handle software handshake. We have to do this before checking the
00186      * buffer, because flow control must work in write-only mode, where
00187      * there is no receive buffer.
00188      */
00189     if (flow_control) {
00190         /* XOFF character disables transmit interrupts. */
00191         if (ch == ASCII_XOFF) {
00192             tx_stop = 1;
00193             outw(REG_SIOCNT, inw(REG_SIOCNT) & ~SIO_SEND_ENA);
00194             flow_control |= XOFF_RCVD;
00195             return;
00196         }
00197         /* XON enables transmit interrupts. */
00198         else if (ch == ASCII_XON) {
00199             tx_stop = 0; //TODO
00200             outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_SEND_ENA);
00201             flow_control &= ~XOFF_RCVD;
00202             return;
00203         }
00204     }
00205 
00206     /*
00207      * Check buffer overflow.
00208      */
00209     cnt = rbf->rbf_cnt;
00210     if (cnt >= rbf->rbf_siz) {
00211         //TODO rx_errors |= _BV(DOR);
00212         return;
00213     }
00214 
00215     /* Wake up waiting threads if this is the first byte in the buffer. */
00216     if (cnt++ == 0) {
00217         NutEventPostFromIrq(&rbf->rbf_que);
00218     }
00219 
00220     /*
00221      * Check the high watermark for software handshake. If the number of 
00222      * buffered bytes is above this mark, then send XOFF.
00223      */
00224     else if (flow_control) {
00225         if (cnt >= rbf->rbf_hwm) {
00226             if ((flow_control & XOFF_SENT) == 0) {
00227                 if (inw(REG_SIOCNT) & SIO_TX_FULL) {
00228                     flow_control |= XOFF_PENDING;
00229                 } else {
00230                     outw(REG_SIODATA8, ASCII_XOFF);
00231                     flow_control |= XOFF_SENT;
00232                     flow_control &= ~XOFF_PENDING;
00233                 }
00234             }
00235         }
00236     }
00237 
00238     /* 
00239      * Store the character and increment and the ring buffer pointer. 
00240      */
00241     *rbf->rbf_head++ = ch;
00242     if (rbf->rbf_head == rbf->rbf_last) {
00243         rbf->rbf_head = rbf->rbf_start;
00244     }
00245 
00246     /* Update the ring buffer counter. */
00247     rbf->rbf_cnt = cnt;
00248 }
00249 
00250 static void GbaUartIsr(void *arg)
00251 {
00252     /* Clear interrupt. */
00253     outw(REG_IF, INT_SIO);
00254 
00255     if ((inw(REG_SIOCNT) & SIO_RX_EMPTY) == 0) {
00256         GbaUartRxFull(&((USARTDCB *) arg)->dcb_rx_rbf);
00257     }
00258     if ((inw(REG_SIOCNT) & SIO_TX_FULL) == 0) {
00259         GbaUartTxEmpty(&((USARTDCB *) arg)->dcb_tx_rbf);
00260     }
00261 }
00262 
00269 static void GbaUartEnable(void)
00270 {
00271     NutEnterCritical();
00272 
00273     //TODO outb(UCSRnB, _BV(RXCIE) | _BV(UDRIE) | _BV(RXEN) | _BV(TXEN));
00274 
00275     NutExitCritical();
00276 }
00277 
00281 static void GbaUartDisable(void)
00282 {
00283     /*
00284      * Disable USART interrupts.
00285      */
00286     //TODO NutEnterCritical();
00287     //TODO cbi(UCSRnB, RXCIE);
00288     //TODO cbi(UCSRnB, TXCIE);
00289     //TODO cbi(UCSRnB, UDRIE);
00290     //TODO NutExitCritical();
00291 
00292     /*
00293      * Allow incoming or outgoing character to finish.
00294      */
00295     //TODO NutDelay(10);
00296 
00297     /*
00298      * Disable USART transmit and receive.
00299      */
00300     //TODO cbi(UCSRnB, RXEN);
00301     //TODO cbi(UCSRnB, TXEN);
00302 }
00303 
00312 static uint32_t GbaUartGetSpeed(void)
00313 {
00314     uint16_t sv = inw(REG_SIOCNT);
00315 
00316     if ((sv & SIO_BAUD_115200) == SIO_BAUD_115200) {
00317         return 115200UL;
00318     }
00319     if ((sv & SIO_BAUD_57600) == SIO_BAUD_57600) {
00320         return 57600UL;
00321     }
00322     if ((sv & SIO_BAUD_38400) == SIO_BAUD_38400) {
00323         return 38400L;
00324     }
00325     return 9600UL;
00326 }
00327 
00338 static int GbaUartSetSpeed(uint32_t rate)
00339 {
00340     uint16_t sv;
00341 
00342     GbaUartDisable();
00343     sv = inw(REG_SIOCNT) & ~SIO_BAUD_115200;
00344     if (rate == 115200) {
00345         sv |= SIO_BAUD_115200;
00346     } else {
00347         if (rate == 57600) {
00348             sv |= SIO_BAUD_57600;
00349         } else if (rate == 38400) {
00350             sv |= SIO_BAUD_38400;
00351         }
00352     }
00353     outw(REG_SIOCNT, sv);
00354     GbaUartEnable();
00355 
00356     return 0;
00357 }
00358 
00367 static uint8_t GbaUartGetDataBits(void)
00368 {
00369     return 8;
00370 }
00371 
00380 static int GbaUartSetDataBits(uint8_t bits)
00381 {
00382     GbaUartDisable();
00383     GbaUartEnable();
00384 
00385     /*
00386      * Verify the result.
00387      */
00388     if (GbaUartGetDataBits() != bits) {
00389         return -1;
00390     }
00391     return 0;
00392 }
00393 
00402 static uint8_t GbaUartGetParity(void)
00403 {
00404     return 0;
00405 }
00406 
00417 static int GbaUartSetParity(uint8_t mode)
00418 {
00419     GbaUartDisable();
00420     GbaUartEnable();
00421 
00422     /*
00423      * Verify the result.
00424      */
00425     if (GbaUartGetParity() != mode) {
00426         return -1;
00427     }
00428     return 0;
00429 }
00430 
00439 static uint8_t GbaUartGetStopBits(void)
00440 {
00441     return 1;
00442 }
00443 
00452 static int GbaUartSetStopBits(uint8_t bits)
00453 {
00454     GbaUartDisable();
00455     GbaUartEnable();
00456 
00457     /*
00458      * Verify the result.
00459      */
00460     if (GbaUartGetStopBits() != bits) {
00461         return -1;
00462     }
00463     return 0;
00464 }
00465 
00471 static uint32_t GbaUartGetStatus(void)
00472 {
00473     uint32_t rc = 0;
00474 
00475     /*
00476      * Set receiver error flags.
00477      */
00478 
00479     /*
00480      * Determine software handshake status. The flow control status may
00481      * change during interrupt, but this doesn't really hurt us.
00482      */
00483     if (flow_control) {
00484         if (flow_control & XOFF_SENT) {
00485             rc |= UART_RXDISABLED;
00486         }
00487         if (flow_control & XOFF_RCVD) {
00488             rc |= UART_TXDISABLED;
00489         }
00490     }
00491 
00492     /*
00493      * If transmitter and receiver haven't been detected disabled by any
00494      * of the checks above, then they are probably enabled.
00495      */
00496     if ((rc & UART_RXDISABLED) == 0) {
00497         rc |= UART_RXENABLED;
00498     }
00499     if ((rc & UART_TXDISABLED) == 0) {
00500         rc |= UART_TXENABLED;
00501     }
00502     return rc;
00503 }
00504 
00512 static int GbaUartSetStatus(uint32_t flags)
00513 {
00514     /*
00515      * Process software handshake control.
00516      */
00517     if (flow_control) {
00518 
00519         /* Access to the flow control status must be atomic. */
00520         NutEnterCritical();
00521 
00522         /*
00523          * Enabling or disabling the receiver means to behave like 
00524          * having sent a XON or XOFF character resp.
00525          */
00526         if (flags & UART_RXENABLED) {
00527             flow_control &= ~XOFF_SENT;
00528         } else if (flags & UART_RXDISABLED) {
00529             flow_control |= XOFF_SENT;
00530         }
00531 
00532         /*
00533          * Enabling or disabling the transmitter means to behave like 
00534          * having received a XON or XOFF character resp.
00535          */
00536         if (flags & UART_TXENABLED) {
00537             flow_control &= ~XOFF_RCVD;
00538         } else if (flags & UART_TXDISABLED) {
00539             flow_control |= XOFF_RCVD;
00540         }
00541         NutExitCritical();
00542     }
00543 
00544     /*
00545      * Verify the result.
00546      */
00547     if ((GbaUartGetStatus() & ~UART_ERRORS) != flags) {
00548         return -1;
00549     }
00550     return 0;
00551 }
00552 
00562 static uint8_t GbaUartGetClockMode(void)
00563 {
00564     return 0;
00565 }
00566 
00578 static int GbaUartSetClockMode(uint8_t mode)
00579 {
00580     /*
00581      * Verify the result.
00582      */
00583     if (GbaUartGetClockMode() != mode) {
00584         return -1;
00585     }
00586     return 0;
00587 }
00588 
00597 static uint32_t GbaUartGetFlowControl(void)
00598 {
00599     uint32_t rc = 0;
00600 
00601     if (flow_control) {
00602         rc |= USART_MF_XONXOFF;
00603     } else {
00604         rc &= ~USART_MF_XONXOFF;
00605     }
00606 
00607     return rc;
00608 }
00609 
00620 static int GbaUartSetFlowControl(uint32_t flags)
00621 {
00622     /*
00623      * Set software handshake mode.
00624      */
00625     if (flags & USART_MF_XONXOFF) {
00626         if (flow_control == 0) {
00627             NutEnterCritical();
00628             flow_control = 1 | XOFF_SENT;       /* force XON to be sent on next read */
00629             NutExitCritical();
00630         }
00631     } else {
00632         NutEnterCritical();
00633         flow_control = 0;
00634         NutExitCritical();
00635     }
00636 
00637     /*
00638      * Verify the result.
00639      */
00640     if (GbaUartGetFlowControl() != flags) {
00641         return -1;
00642     }
00643     return 0;
00644 }
00645 
00653 static void GbaUartTxStart(void)
00654 {
00655     RINGBUF *rbf = &dcb_uart.dcb_tx_rbf;
00656     register uint8_t *cp = rbf->rbf_tail;
00657 
00658     NutEnterCritical();
00659     if(tx_stop) {
00660         if (rbf->rbf_cnt) {
00661             rbf->rbf_cnt--;
00662             outw(REG_SIODATA8, *cp);
00663             if (++cp == rbf->rbf_last) {
00664                 cp = rbf->rbf_start;
00665             }
00666             rbf->rbf_tail = cp;
00667             tx_stop = 0;
00668         }
00669     }
00670     outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_SEND_ENA);
00671     NutExitCritical();
00672 }
00673 
00682 static void GbaUartRxStart(void)
00683 {
00684     /*
00685      * Do any required software flow control.
00686      */
00687     NutEnterCritical();
00688     if (flow_control && (flow_control & XOFF_SENT) != 0) {
00689         if (inw(REG_SIOCNT) & SIO_TX_FULL) {
00690             flow_control |= XON_PENDING;
00691         } else {
00692             outw(REG_SIODATA8, ASCII_XON);
00693             flow_control &= ~XON_PENDING;
00694         }
00695         flow_control &= ~(XOFF_SENT | XOFF_PENDING);
00696     }
00697     outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_RECV_ENA);
00698     NutExitCritical();
00699 }
00700 
00701 /*
00702  * \brief Initialize the USART hardware driver.
00703  *
00704  * This function is called during device registration by the upper level 
00705  * USART driver through the USARTDCB jump table.
00706  *
00707  * \return 0 on success, -1 otherwise.
00708  */
00709 static int GbaUartInit(void)
00710 {
00711     int rc;
00712 
00713     /*
00714      * Activate MBV2 UART mode by setting SC low and SD high for at 
00715      * least 50 milliseconds.
00716      */
00717     outw(REG_RCNT, 0x8032);
00718     NutSleep(100);
00719 
00720     /* Disable master interrupt. */
00721     outw(REG_IME, 0);
00722 
00723     /* Register our interrupt service. */
00724     if((rc = NutRegisterIrqHandler(&sig_SIO, GbaUartIsr, &dcb_uart)) == 0) {
00725 
00726         /* Enable UART mode. */
00727         outw(REG_RCNT, 0x0000);
00728 
00729         /* Set UART mode */
00730         outw(REG_SIOCNT, SIO_IRQ_ENA | SIO_MODE_UART | SIO_DATA_8BIT | SIO_BAUD_38400);
00731 
00732         /* Clear receive/transmit */
00733         outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_RX_EMPTY | SIO_TX_FULL);
00734 
00735         /* Enable FIFO. */
00736         //outw(REG_SIOCNT, inw(REG_SIOCNT) | SIO_FIFO_ENA);
00737 
00738         /* Enable SIO interrupts. */
00739         outw(REG_IE, inw(REG_IE) | INT_SIO);
00740     }
00741 
00742     printf("I[%04X]", inw(REG_SIOCNT));
00743 
00744     /* Enable master interrupt. */
00745     outw(REG_IME, 1);
00746 
00747     return rc;
00748 }
00749 
00750 /*
00751  * \brief Deinitialize the USART hardware driver.
00752  *
00753  * This function is called during device deregistration by the upper 
00754  * level USART driver through the USARTDCB jump table.
00755  *
00756  * \return 0 on success, -1 otherwise.
00757  */
00758 static int GbaUartDeinit(void)
00759 {
00760     /* Deregister receive and transmit interrupts. */
00761     NutRegisterIrqHandler(&sig_SIO, 0, 0);
00762 
00763     return 0;
00764 }
00765 
00766 #if 1
00767 
00770 static USARTDCB dcb_uart = {
00771     0,                          /* dcb_modeflags */
00772     0,                          /* dcb_statusflags */
00773     0,                          /* dcb_rtimeout */
00774     0,                          /* dcb_wtimeout */
00775     {0, 0, 0, 0, 0, 0, 0, 0},   /* dcb_tx_rbf */
00776     {0, 0, 0, 0, 0, 0, 0, 0},   /* dcb_rx_rbf */
00777     0,                          /* dbc_last_eol */
00778     GbaUartInit,                /* dcb_init */
00779     GbaUartDeinit,              /* dcb_deinit */
00780     GbaUartTxStart,             /* dcb_tx_start */
00781     GbaUartRxStart,             /* dcb_rx_start */
00782     GbaUartSetFlowControl,      /* dcb_set_flow_control */
00783     GbaUartGetFlowControl,      /* dcb_get_flow_control */
00784     GbaUartSetSpeed,            /* dcb_set_speed */
00785     GbaUartGetSpeed,            /* dcb_get_speed */
00786     GbaUartSetDataBits,         /* dcb_set_data_bits */
00787     GbaUartGetDataBits,         /* dcb_get_data_bits */
00788     GbaUartSetParity,           /* dcb_set_parity */
00789     GbaUartGetParity,           /* dcb_get_parity */
00790     GbaUartSetStopBits,         /* dcb_set_stop_bits */
00791     GbaUartGetStopBits,         /* dcb_get_stop_bits */
00792     GbaUartSetStatus,           /* dcb_set_status */
00793     GbaUartGetStatus,           /* dcb_get_status */
00794     GbaUartSetClockMode,        /* dcb_set_clock_mode */
00795     GbaUartGetClockMode,        /* dcb_get_clock_mode */
00796 };
00797 
00813 NUTDEVICE devUartGba = {
00814     0,                          /* Pointer to next device, dev_next. */
00815     {'u', 'a', 'r', 't', '0', 0, 0, 0, 0},      /* Unique device name, dev_name. */
00816     IFTYP_CHAR,                 /* Type of device, dev_type. */
00817     0,                          /* Base address, dev_base (not used). */
00818     0,                          /* First interrupt number, dev_irq (not used). */
00819     0,                          /* Interface control block, dev_icb (not used). */
00820     &dcb_uart,                  /* Driver control block, dev_dcb. */
00821     UsartInit,                  /* Driver initialization routine, dev_init. */
00822     UsartIOCtl,                 /* Driver specific control function, dev_ioctl. */
00823     UsartRead,                  /* Read from device, dev_read. */
00824     UsartWrite,                 /* Write to device, dev_write. */
00825     UsartOpen,                  /* Open a device or file, dev_open. */
00826     UsartClose,                 /* Close a device or file, dev_close. */
00827     UsartSize                   /* Request file size, dev_size. */
00828 };
00829 #endif
00830