⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uartavr.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * *//* * $Log: uartavr.c,v $ * Revision 1.3  2005/10/16 23:21:33  hwmaier * Fixed compilation issue regards U2X macro with Imagecraft * * Revision 1.2  2005/10/07 22:01:27  hwmaier * Obsolete dcb_baudSelect removed. Support for double speed (U2X) added (using same method as in usartavr.c). * * Revision 1.1  2005/07/26 18:02:40  haraldkipp * Moved from dev. * * Revision 1.9  2005/07/14 09:12:20  freckle * Rewrote CS in UartAvrInput * * Revision 1.8  2005/01/24 21:12:05  freckle * renamed NutEventPostFromIRQ into NutEventPostFromIrq * * Revision 1.7  2005/01/21 16:49:46  freckle * Seperated calls to NutEventPostAsync between Threads and IRQs * * Revision 1.6  2004/12/16 08:40:35  haraldkipp * Late increment fixes ICCAVR bug. * * Revision 1.5  2004/05/24 20:15:50  drsung * Added function UartAvrSize to return number of chars in input buffer. * * Revision 1.4  2004/03/18 14:01:07  haraldkipp * Deprecated header file replaced * * Revision 1.3  2004/03/18 10:09:27  haraldkipp * Removed deprecated raw I/O * * Revision 1.2  2003/07/20 18:28:10  haraldkipp * Explain how to disable timeout. * * Revision 1.1.1.1  2003/05/09 14:40:55  haraldkipp * Initial using 3.2.1 * * Revision 1.21  2003/05/06 18:35:06  harald * Avoid duplicate initialization * * Revision 1.20  2003/04/21 16:26:01  harald * Use predefined eof * * Revision 1.19  2003/03/31 14:53:08  harald * Prepare release 3.1 * */#include <string.h>#include <sys/atom.h>#include <sys/heap.h>#include <sys/event.h>#include <sys/timer.h>#include <sys/device.h>#include <dev/irqreg.h>#include <dev/uartavr.h>#include <fcntl.h>/* * Not nice because stdio already defined them. But in order to save memory, * we do the whole buffering and including stdio here would be more weird. */#ifndef _IOFBF#define _IOFBF	    0x00#define _IOLBF	    0x01#define _IONBF	    0x02#endif/*! * \addtogroup xgUartAvr *//*@{*//* * Handle AVR UART transmit complete. */static void TxComplete(void *arg){    NUTDEVICE *dev = (NUTDEVICE *) arg;    IFSTREAM *ifs = dev->dev_icb;    UARTDCB *dcb;    if (ifs->if_tx_idx != ifs->if_wr_idx) {#ifdef UDR1        if (dev->dev_base)            UDR1 = ifs->if_tx_buf[ifs->if_tx_idx];        else#endif            outp(ifs->if_tx_buf[ifs->if_tx_idx], UDR);        ifs->if_tx_idx++;    } else {        ifs->if_tx_act = 0;        dcb = dev->dev_dcb;        NutEventPostFromIrq(&dcb->dcb_tx_rdy);    }}/* * Handle AVR UART receive complete. * * Note, that this function modifies the receive index in * interrupt context. This requires, that any non atomic * access of this index requires interrupts being disabled. * Thanks to Mike Cornelius, who pointed this out. */static void RxComplete(void *arg){    NUTDEVICE *dev = (NUTDEVICE *) arg;    IFSTREAM *ifs = dev->dev_icb;    UARTDCB *dcb;#ifdef UDR1    if (dev->dev_base)        ifs->if_rx_buf[ifs->if_rx_idx] = inp(UDR1);    else#endif        ifs->if_rx_buf[ifs->if_rx_idx] = inp(UDR);    if (ifs->if_rd_idx == ifs->if_rx_idx) {        dcb = dev->dev_dcb;        NutEventPostFromIrq(&dcb->dcb_rx_rdy);    }    /* Late increment fixes ICCAVR bug on volatile variables. */    ifs->if_rx_idx++;}/*! * \brief Wait for input. * * This function checks the input buffer for any data. If * the buffer is empty, the calling \ref xrThread "thread" * will be blocked until at least one new character is * received or a timeout occurs. * * \param dev Indicates the UART device. * * \return 0 on success, -1 on timeout. */int UartAvrInput(NUTDEVICE * dev){    int rc = 0;    int empty;    IFSTREAM *ifs = dev->dev_icb;    UARTDCB *dcb =  dev->dev_dcb;    NutEnterCritical();    empty = ifs->if_rd_idx == ifs->if_rx_idx;    NutExitCritical();    if (empty) {        /*         * Changing if into a while loop fixes a serious bug:         * Previous receiver events without any waiting thread         * set the event handle to the signaled state. So the         * wait returns immediately. Unfortunately the calling         * routines rely on a filled buffer when we return 0.         * Thanks to Mike Cornelius, who found this bug.         *         * MR (2005-07-14): Reduced critical sections         */        do {            rc = NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout);            NutEnterCritical();            empty = ifs->if_rd_idx == ifs->if_rx_idx;            NutExitCritical();        } while (rc == 0 && empty);    }    return rc;}/*! * \brief Initiate output. * * This function checks the output buffer for any data. If * the buffer contains at least one character, the transmitter * is started, if not already running. The function returns * immediately, without waiting for the character being * completely transmitted. Any remaining characters in the * output buffer are transmitted in the background. * * \param dev Indicates the UART device. * * \return 0 on success, -1 otherwise. */int UartAvrOutput(NUTDEVICE * dev){    IFSTREAM *ifs = dev->dev_icb;    if (ifs->if_tx_act == 0 && ifs->if_tx_idx != ifs->if_wr_idx) {        ifs->if_tx_act = 1;#ifdef UDR1        if (dev->dev_base)            UDR1 = ifs->if_tx_buf[ifs->if_tx_idx];        else#endif            outp(ifs->if_tx_buf[ifs->if_tx_idx], UDR);        ifs->if_tx_idx++;    }    return 0;}/*! * \brief Wait for output buffer empty. * * If the output buffer contains any data, the calling * thread is suspended until all data has been transmitted. * * \param dev Indicates the UART device. * * \return 0 on success, -1 otherwise. */int UartAvrFlush(NUTDEVICE * dev){    IFSTREAM *ifs = dev->dev_icb;    UARTDCB *dcb = dev->dev_dcb;    /*     * Start any pending output.     */    if (UartAvrOutput(dev))        return -1;    /*     * Wait until output buffer empty.     */    NutEnterCritical();    while (ifs->if_tx_idx != ifs->if_wr_idx)        NutEventWait(&dcb->dcb_tx_rdy, 100);    NutExitCritical();    return 0;}/* * * \param dev Indicates the UART device. * * \return 0 on success, -1 otherwise. */static int UartAvrGetStatus(NUTDEVICE * dev, u_long * status){    IFSTREAM *ifs = dev->dev_icb;    u_char us;    *status = 0;#ifdef UDR1    if (dev->dev_base)        us = inp(UCSR1A);    else#endif        us = inp(USR);    if (us & FE)        *status |= UART_FRAMINGERROR;    if (us & DOR)        *status |= UART_OVERRUNERROR;    if (ifs->if_tx_idx == ifs->if_wr_idx)        *status |= UART_TXBUFFEREMPTY;    if (ifs->if_rd_idx == ifs->if_rx_idx)        *status |= UART_RXBUFFEREMPTY;    return 0;}/* * Carefully enable UART functions. */static void UartAvrEnable(u_short base){    NutEnterCritical();#ifdef UCSR1B    if (base)        UCSR1B = BV(RXCIE) | BV(TXCIE) | BV(RXEN) | BV(TXEN);    else#endif        UCR = BV(RXCIE) | BV(TXCIE) | BV(RXEN) | BV(TXEN);    NutExitCritical();}/* * Carefully disable UART functions. */static void UartAvrDisable(u_short base){    /*     * Disable UART interrupts.     */    NutEnterCritical();#ifdef UCSR1B    if (base)        UCSR1B &= ~(BV(RXCIE) | BV(TXCIE));    else#endif        UCR &= ~(BV(RXCIE) | BV(TXCIE));    NutExitCritical();    /*     * Allow incoming or outgoing character to finish.     */    NutDelay(10);    /*     * Now disable UART functions.     */#ifdef UCSR1B    if (base)        UCSR1B &= ~(BV(RXEN) | BV(TXEN));    else#endif        UCR &= ~(BV(RXEN) | BV(TXEN));}/*! * \brief Perform on-chip UART control functions. * * \param dev  Identifies the device that receives the device-control *             function. * \param req  Requested control function. May be set to one of the *             following constants: *             - UART_SETSPEED, conf points to an u_long value containing the baudrate. *             - UART_GETSPEED, conf points to an u_long value receiving the current baudrate. *             - UART_SETDATABITS, conf points to an u_long value containing the number of data bits, 5, 6, 7 or 8. *             - UART_GETDATABITS, conf points to an u_long value receiving the number of data bits, 5, 6, 7 or 8. *             - UART_SETPARITY, conf points to an u_long value containing the parity, 0 (no), 1 (odd) or 2 (even). *             - UART_GETPARITY, conf points to an u_long value receiving the parity, 0 (no), 1 (odd) or 2 (even). *             - UART_SETSTOPBITS, conf points to an u_long value containing the number of stop bits 1 or 2. *             - UART_GETSTOPBITS, conf points to an u_long value receiving the number of stop bits 1 or 2. *             - UART_SETSTATUS *             - UART_GETSTATUS *             - UART_SETREADTIMEOUT, conf points to an u_long value containing the read timeout. *             - UART_GETREADTIMEOUT, conf points to an u_long value receiving the read timeout. *             - UART_SETWRITETIMEOUT, conf points to an u_long value containing the write timeout. *             - UART_GETWRITETIMEOUT, conf points to an u_long value receiving the write timeout. *             - UART_SETLOCALECHO, conf points to an u_long value containing 0 (off) or 1 (on). *             - UART_GETLOCALECHO, conf points to an u_long value receiving 0 (off) or 1 (on). *             - UART_SETFLOWCONTROL, conf points to an u_long value containing combined UART_FCTL_ values. *             - UART_GETFLOWCONTROL, conf points to an u_long value containing receiving UART_FCTL_ values. *             - UART_SETCOOKEDMODE, conf points to an u_long value containing 0 (off) or 1 (on). *             - UART_GETCOOKEDMODE, conf points to an u_long value receiving 0 (off) or 1 (on). * * \param conf Points to a buffer that contains any data required for *             the given control function or receives data from that *             function. * \return 0 on success, -1 otherwise. * * \warning Timeout values are given in milliseconds and are limited to *          the granularity of the system timer. To disable timeout, *          set the parameter to NUT_WAIT_INFINITE. * * \bug For ATmega103, only 8 data bits, 1 stop bit and no parity are allowed. * */int UartAvrIOCtl(NUTDEVICE * dev, int req, void *conf){    int rc = 0;    UARTDCB *dcb;    u_long *lvp = (u_long *) conf;    u_long lv = *lvp;    u_char bv = (u_char) lv;    u_short sv;    u_char devnum;    if (dev == 0)        dev = &devUart0;    devnum = dev->dev_base;    dcb = dev->dev_dcb;    switch (req) {    case UART_SETSPEED:        UartAvrDisable(devnum);#ifdef __AVR_ENHANCED__        if (devnum) {            if (bit_is_set(UCSR1A, U2X1)) {                lv <<= 2;            } else {                lv <<= 3;            }        } else {            if (bit_is_set(UCSR0A, U2X0)) {                lv <<= 2;            } else {                lv <<= 3;            }        }#else        lv <<= 3;#endif        sv = (u_short) ((NutGetCpuClock() / lv + 1UL) / 2UL) - 1;#ifdef UBRR1H        if (devnum) {            UBRR1L = (u_char) sv;            UBRR1H = (u_char) (sv >> 8);        } else {            UBRR0L = (u_char) sv;            UBRR0H = (u_char) (sv >> 8);        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -