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

📄 usartat91.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001-2005 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/ * * The 9-bit communication had been contributed by Brett Abbott, * Digital Telemetry Limited. * * Dave Smart contributed the synchronous mode support. *//* * $Log: usartat91.c,v $ * Revision 1.1  2005/11/20 14:40:28  haraldkipp * Added interrupt driven UART driver for AT91. * */#include <sys/atom.h>#include <sys/event.h>#include <sys/timer.h>#include <dev/irqreg.h>#include <dev/usartat91.h>/*! * \addtogroup xgUsartAt91 *//*@{*//* \brief ASCII code for software flow control, starts transmitter. */#define ASCII_XON   0x11/* \brief ASCII code for software flow control, stops transmitter. */#define ASCII_XOFF  0x13/* \brief XON transmit pending flag. */#define XON_PENDING     0x10/* \brief XOFF transmit pending flag. */#define XOFF_PENDING    0x20/* \brief XOFF sent flag. */#define XOFF_SENT       0x40/* \brief XOFF received flag. */#define XOFF_RCVD       0x80/*! * \brief Receiver error flags. */static ureg_t rx_errors;/*! * \brief Enables software flow control if not equal zero. */static ureg_t flow_control;/*! * \brief Transmit address frame, if not zero. */static ureg_t tx_aframe;#ifdef UART_HDX_BIT	/* define in cfg/modem.h */	#ifdef UART_HDX_FLIP_BIT	/* same as RTS toggle by Windows NT driver */		#define UART_HDX_TX		cbi		#define UART_HDX_RX		sbi	#else						/* previous usage by Ethernut */		#define UART_HDX_TX		sbi		#define UART_HDX_RX		cbi	#endif#endif#ifdef UART_HDX_BIT/*! * \brief Enables half duplex control if not equal zero. * * This variable exists only if the hardware configuration defines a * port bit to switch between receive and transmit mode. */static ureg_t hdx_control;#endif#ifdef UART_RTS_BIT/*! * \brief Enables RTS control if not equal zero. * * This variable exists only if the hardware configuration defines a * port bit to control the RTS signal. */static ureg_t rts_control;#endif#ifdef UART_CTS_BIT/*! * \brief Enables CTS sense if not equal zero. * * This variable exists only if the hardware configuration defines a * port bit to sense the CTS signal. */static ureg_t cts_sense;#endif#ifdef UART_CTS_BIT/*! * \brief USARTn CTS sense interrupt handler. * * This interrupt routine is called when the CTS line level is low. * Typical line drivers negate the signal, thus driving our port * low when CTS is active. * * This routine exists only if the hardware configuration defines a * port bit to sense the CTS signal. */static void At91UsartCts(void *arg){    /* Enable transmit interrupt. */    //sbi(UCSRnB, UDRIE);    /* Disable CTS sense interrupt. */    //cbi(EIMSK, UART_CTS_BIT);}#endif#ifdef UART_HDX_BIT/* * \brief USARTn transmitter empty interrupt handler. * * Used with half duplex communication to switch from tranmit to receive * mode after the last character has been transmitted. * * This routine exists only if the hardware configuration defines a * port bit to switch between receive and transmit mode. * * \param arg Pointer to the transmitter ring buffer. */static void At91UsartTxEmpty(RINGBUF *rbf){    /*     * Check if half duplex mode has been enabled and if all characters     * had been sent out.     */    if (hdx_control && rbf->rbf_cnt == 0) {        /* Switch to receiver mode. */        UART_HDX_RX(UART_HDX_PORT, UART_HDX_BIT);    }}#endif/* * \brief USARTn transmitter ready interrupt handler. * * \param rbf Pointer to the transmitter ring buffer. */static void At91UsartTxReady(RINGBUF *rbf) {    register u_char *cp = rbf->rbf_tail;    /*     * Process pending software flow controls first.     */    if (flow_control & (XON_PENDING | XOFF_PENDING)) {        if (flow_control & XON_PENDING) {            outr(USARTn_BASE + US_THR_OFF, ASCII_XOFF);            flow_control |= XOFF_SENT;        } else {            outr(USARTn_BASE + US_THR_OFF, ASCII_XON);            flow_control &= ~XOFF_SENT;        }        flow_control &= ~(XON_PENDING | XOFF_PENDING);        return;    }    if (flow_control & XOFF_RCVD) {        /*         * If XOFF has been received, we disable the transmit interrupts         * and return without sending anything.         */        outr(USARTn_BASE + US_IDR_OFF, US_TXRDY);        return;	}    if (rbf->rbf_cnt) {#ifdef UART_CTS_BIT        /*         * If CTS has been disabled, we disable the transmit interrupts         * and return without sending anything.         */        if (cts_sense && bit_is_set(UART_CTS_PIN, UART_CTS_BIT)) {            outr(USARTn_BASE + US_IDR_OFF, US_TXRDY);            sbi(EIMSK, UART_CTS_BIT);            return;        }#endif        rbf->rbf_cnt--;        /*         * Send address in multidrop mode.         */        if (tx_aframe) {            outr(USARTn_BASE + US_CR_OFF, US_SENDA);        }        /*         * Start transmission of the next character.         */        outr(USARTn_BASE + US_THR_OFF, *cp);        /*         * Wrap around the buffer pointer if we reached its end.         */        if (++cp == rbf->rbf_last) {            cp = rbf->rbf_start;        }        rbf->rbf_tail = cp;        if (rbf->rbf_cnt == rbf->rbf_lwm) {            NutEventPostFromIrq(&rbf->rbf_que);        }    }    /*     * Nothing left to transmit, disable interrupt.     */    else {        outr(USARTn_BASE + US_IDR_OFF, US_TXRDY);        rbf->rbf_cnt = 0;        NutEventPostFromIrq(&rbf->rbf_que);    }}/* * \brief USARTn receiver ready interrupt handler. * * * \param rbf Pointer to the receiver ring buffer. */static void At91UsartRxReady(RINGBUF *rbf) {    register size_t cnt;    register u_char ch;    /*     * We read the received character as early as possible to avoid overflows     * caused by interrupt latency.     */    ch = inb(USARTn_BASE + US_RHR_OFF);    /* Collect receiver errors. */    rx_errors |= inr(USARTn_BASE + US_CSR_OFF) & (US_OVRE | US_FRAME | US_PARE);    /*     * Handle software handshake. We have to do this before checking the     * buffer, because flow control must work in write-only mode, where     * there is no receive buffer.     */    if (flow_control) {        /* XOFF character disables transmit interrupts. */        if (ch == ASCII_XOFF) {            outr(USARTn_BASE + US_IDR_OFF, US_TXRDY);            flow_control |= XOFF_RCVD;            return;        }        /* XON enables transmit interrupts. */        else if (ch == ASCII_XON) {            outr(USARTn_BASE + US_IER_OFF, US_TXRDY);            flow_control &= ~XOFF_RCVD;            return;        }    }    /*     * Check buffer overflow.     */    cnt = rbf->rbf_cnt;    if (cnt >= rbf->rbf_siz) {        rx_errors |= US_OVRE;        return;    }    /* Wake up waiting threads if this is the first byte in the buffer. */    if (cnt++ == 0){        NutEventPostFromIrq(&rbf->rbf_que);    }    /*     * Check the high watermark for software handshake. If the number of     * buffered bytes is above this mark, then send XOFF.     */    else if (flow_control) {        if(cnt >= rbf->rbf_hwm) {            if((flow_control & XOFF_SENT) == 0) {                if (inr(USARTn_BASE + US_CSR_OFF) & US_TXRDY) {                    outb(USARTn_BASE + US_THR_OFF, ASCII_XOFF);                    flow_control |= XOFF_SENT;                    flow_control &= ~XOFF_PENDING;                } else {                    flow_control |= XOFF_PENDING;                }            }        }    }#ifdef UART_RTS_BIT    /*     * Check the high watermark for hardware handshake. If the number of     * buffered bytes is above this mark, then disable RTS.     */    else if (rts_control && cnt >= rbf->rbf_hwm) {        sbi(UART_RTS_PORT, UART_RTS_BIT);    }#endif    /*     * Store the character and increment and the ring buffer pointer.     */    *rbf->rbf_head++ = ch;    if (rbf->rbf_head == rbf->rbf_last) {        rbf->rbf_head = rbf->rbf_start;    }    /* Update the ring buffer counter. */    rbf->rbf_cnt = cnt;}/*! * \brief USART interrupt handler. * * \param arg Pointer to the device specific control block. */static void At91UsartInterrupt(void *arg){    USARTDCB *dcb = (USARTDCB *)arg;    ureg_t csr = inr(USARTn_BASE + US_CSR_OFF);    if (csr & US_RXRDY) {        At91UsartRxReady(&dcb->dcb_rx_rbf);    }    if (csr & US_TXRDY) {        At91UsartTxReady(&dcb->dcb_tx_rbf);    }#ifdef UART_HDX_BIT    if (csr & US_TXEMPTY) {        At91UsartTxEmpty(&dcb->dcb_tx_rbf);    }#endif /*  UART_HDX_BIT */}/*! * \brief Carefully enable USART hardware functions. * * Always enabale transmitter and receiver, even on read-only or * write-only mode. So we can support software flow control. */static void At91UsartEnable(void){    NutEnterCritical();    /* Enable UART receiver and transmitter. */    outr(USARTn_BASE + US_CR_OFF, US_RXEN | US_TXEN);    /* Enable UART receiver and transmitter interrupts. */    outr(USARTn_BASE + US_IER_OFF, US_RXRDY | US_TXRDY);    NutIrqEnable(&SIG_UART);#ifdef UART_HDX_BIT    if (hdx_control) {        /* Enable transmit complete interrupt. */        sbi(UCSRnB, TXCIE);    }#endif    NutExitCritical();}/*! * \brief Carefully disable USART hardware functions. */static void At91UsartDisable(void){    /*     * Disable USART interrupts.     */    NutEnterCritical();    outr(USARTn_BASE + US_IDR_OFF, 0xFFFFFFFF);    NutExitCritical();    /*     * Allow incoming or outgoing character to finish.     */    NutDelay(10);    /*     * Disable USART transmit and receive.     */    outr(USARTn_BASE + US_CR_OFF, US_RXDIS | US_TXDIS);}/*! * \brief Query the USART hardware for the selected speed. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return The currently selected baudrate. */static u_long At91UsartGetSpeed(void){    ureg_t cs = inr(USARTn_BASE + US_MR_OFF);    u_long clk;    if ((cs & US_CLKS) == US_CLKS_MCK) {        clk = NutGetCpuClock();    }    else if ((cs & US_CLKS) == US_CLKS_MCK8) {        clk = NutGetCpuClock() / 8;    }    else {        clk = 0;    }    return clk / (16UL * (inr(USARTn_BASE + US_BRGR_OFF) & 0xFFFF));}/*! * \brief Set the USART hardware bit rate. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \param rate Number of bits per second. * * \return 0 on success, -1 otherwise. */static int At91UsartSetSpeed(u_long rate){    At91UsartDisable();    outr(USARTn_BASE + US_BRGR_OFF, AT91_US_BAUD(rate));    At91UsartEnable();    return 0;}/*! * \brief Query the USART hardware for the number of data bits. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return The number of data bits set. */static u_char At91UsartGetDataBits(void){    ureg_t val = inr(USARTn_BASE + US_MR_OFF);    if ((val & US_PAR) == US_PAR_MULTIDROP) {        val = 9;    }    else {        val &= US_CHRL;        if (val == US_CHRL_5) {            val = 5;        }        else if (val == US_CHRL_6) {            val = 6;        }        else if (val == US_CHRL_7) {            val = 7;        }        else {            val = 8;        }    }    return (u_char)val;}/*! * \brief Set the USART hardware to the number of data bits. * * This function is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return 0 on success, -1 otherwise. */static int At91UsartSetDataBits(u_char bits){    ureg_t val = inr(USARTn_BASE + US_MR_OFF);    if (bits == 9) {        val &= ~US_PAR;        val |= US_PAR_MULTIDROP;    }    else {        val &= ~US_CHRL;        if (bits == 5) {            val |= US_CHRL_5;        }        else if (bits == 6) {            val |= US_CHRL_6;        }        else if (bits == 7) {            val |= US_CHRL_7;        }        else if (bits == 8) {            val |= US_CHRL_8;        }    }    At91UsartDisable();    outr(USARTn_BASE + US_MR_OFF, val);    At91UsartEnable();    /*     * Verify the result.     */    if (At91UsartGetDataBits() != bits) {        return -1;    }    return 0;}/*! * \brief Query the USART hardware for the parity mode. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table. * * \return Parity mode, either 0 (disabled), 1 (odd), 2 (even) or 9 (multidrop). */static u_char At91UsartGetParity(void){    ureg_t val = inr(USARTn_BASE + US_MR_OFF) & US_PAR;    if ((val & US_PAR) == US_PAR_MULTIDROP) {        val = 9;    }    else {        if (val == US_PAR_ODD) {            val = 1;        }        else if (val == US_PAR_EVEN) {            val = 2;        }        else {            val = 0;        }    }    return (u_char)val;}/*! * \brief Set the USART hardware to the specified parity mode. * * This routine is called by ioctl function of the upper level USART * driver through the USARTDCB jump table.

⌨️ 快捷键说明

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