| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353 |
- /*
- * 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 THE COPYRIGHT HOLDERS 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 THE
- * COPYRIGHT OWNER 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.
- */
- /*!
- * \file arch/avr/dev/usartavr.c
- * \brief AVR USART support.
- *
- * \verbatim
- * $Id: usartavr.c 5472 2013-12-06 00:16:28Z olereinhardt $
- * \endverbatim
- */
- #include <sys/atom.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <dev/irqreg.h>
- #include <dev/usartavr.h>
- #ifdef NUTTRACER
- #include <sys/tracer.h>
- #endif
- /*!
- * \addtogroup xgUsartAvr
- */
- /*@{*/
- /* \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 AvrUsartCts(void *arg)
- {
- /* Enable transmit interrupt. */
- sbi(UCSRnB, UDRIE);
- /* Disable CTS sense interrupt. */
- cbi(EIMSK, UART_CTS_BIT);
- }
- #endif
- #ifdef UART_HDX_BIT
- /*
- * \brief USARTn transmit complete 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 AvrUsartTxComplete(void *arg)
- {
- register RINGBUF *rbf = (RINGBUF *) arg;
- /*
- * 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 transmit data register empty interrupt handler.
- *
- * \param arg Pointer to the transmitter ring buffer.
- */
- #ifdef USE_USART
- SIGNAL( SIG_AVRUART_DATA ) {
- register RINGBUF *rbf = &dcb_usart.dcb_tx_rbf;
- #else
- static void AvrUsartTxEmpty(void *arg) {
- register RINGBUF *rbf = (RINGBUF *) arg;
- #endif
- register uint8_t *cp = rbf->rbf_tail;
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_ENTER,TRACE_INT_UART_TXEMPTY);
- #endif
- #ifndef UART_NO_SW_FLOWCONTROL
- /*
- * Process pending software flow controls first.
- */
- if (flow_control & (XON_PENDING | XOFF_PENDING)) {
- if (flow_control & XON_PENDING) {
- outb(UDRn, ASCII_XOFF);
- flow_control |= XOFF_SENT;
- } else {
- outb(UDRn, ASCII_XON);
- flow_control &= ~XOFF_SENT;
- }
- flow_control &= ~(XON_PENDING | XOFF_PENDING);
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_TXEMPTY);
- #endif
- return;
- }
- if (flow_control & XOFF_RCVD) {
- /*
- * If XOFF has been received, we disable the transmit interrupts
- * and return without sending anything.
- */
- cbi(UCSRnB, UDRIE);
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_TXEMPTY);
- #endif
- return;
- }
- #endif /* UART_NO_SW_FLOWCONTROL */
- 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)) {
- cbi(UCSRnB, UDRIE);
- sbi(EIMSK, UART_CTS_BIT);
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_TXEMPTY);
- #endif
- return;
- }
- #endif
- rbf->rbf_cnt--;
- /*
- * The data sheet doesn't exactly tell us, if this bit is retained
- * or cleared after the character has been sent out. So we do it
- * the save way.
- */
- if (tx_aframe) {
- sbi(UCSRnB, TXB8);
- } else {
- cbi(UCSRnB, TXB8);
- }
- /*
- * Start transmission of the next character.
- */
- outb(UDRn, *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);
- NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_WRITE);
- }
- }
- /*
- * Nothing left to transmit, disable interrupt.
- */
- else {
- cbi(UCSRnB, UDRIE);
- rbf->rbf_cnt = 0;
- NutEventPostFromIrq(&rbf->rbf_que);
- NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_WRITE);
- }
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_TXEMPTY);
- #endif
- }
- /*
- * \brief USARTn receive complete interrupt handler.
- *
- *
- * \param arg Pointer to the receiver ring buffer.
- */
- #ifdef USE_USART
- SIGNAL( SIG_AVRUART_RECV ){
- register RINGBUF *rbf = &dcb_usart.dcb_rx_rbf;
- #else
- static void AvrUsartRxComplete(void *arg) {
- register RINGBUF *rbf = (RINGBUF *) arg;
- #endif
- register size_t cnt;
- register uint8_t ch;
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_ENTER,TRACE_INT_UART_RXCOMPL);
- #endif
- #ifdef UART_READMULTIBYTE
- register uint8_t postEvent = 0;
- do {
- #endif
- /*
- * We read the received character as early as possible to avoid overflows
- * caused by interrupt latency. However, reading the error flags must come
- * first, because reading the ATmega128 data register clears the status.
- */
- rx_errors |= inb(UCSRnA);
- ch = inb(UDRn);
- #ifndef UART_NO_SW_FLOWCONTROL
- /*
- * 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) {
- cbi(UCSRnB, UDRIE);
- flow_control |= XOFF_RCVD;
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_RXCOMPL);
- #endif
- return;
- }
- /* XON enables transmit interrupts. */
- else if (ch == ASCII_XON) {
- sbi(UCSRnB, UDRIE);
- flow_control &= ~XOFF_RCVD;
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_RXCOMPL);
- #endif
- return;
- }
- }
- #endif
- /*
- * Check buffer overflow.
- */
- cnt = rbf->rbf_cnt;
- if (cnt >= rbf->rbf_siz) {
- rx_errors |= _BV(DOR);
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_RXCOMPL);
- #endif
- return;
- }
- /* Wake up waiting threads if this is the first byte in the buffer. */
- if (cnt++ == 0){
- #ifdef UART_READMULTIBYTE
- // we do this later, to get the other bytes in time..
- postEvent = 1;
- #else
- NutEventPostFromIrq(&rbf->rbf_que);
- NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_READ);
- #endif
- }
- #ifndef UART_NO_SW_FLOWCONTROL
- /*
- * 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 (inb(UCSRnA) & _BV(UDRE)) {
- outb(UDRn, ASCII_XOFF);
- flow_control |= XOFF_SENT;
- flow_control &= ~XOFF_PENDING;
- } else {
- flow_control |= XOFF_PENDING;
- }
- }
- }
- }
- #endif
- #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;
- #ifdef UART_READMULTIBYTE
- } while ( inb(UCSRnA) & _BV(RXC) ); // byte in buffer?
- // Eventually post event to wake thread
- if (postEvent) {
- NutEventPostFromIrq(&rbf->rbf_que);
- NutSelectWakeupFromIrq(rbf->wq_list, WQ_FLAG_READ);
- }
- #endif
- #ifdef NUTTRACER
- TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_UART_RXCOMPL);
- #endif
- }
- /*!
- * \brief Carefully enable USART hardware functions.
- *
- * Always enable transmitter and receiver, even on read-only or
- * write-only mode. So we can support software flow control.
- */
- static void AvrUsartEnable(void)
- {
- NutEnterCritical();
- outb(UCSRnB, _BV(RXCIE) | _BV(UDRIE) | _BV(RXEN) | _BV(TXEN));
- #ifdef UART_HDX_BIT
- if (hdx_control) {
- /* Enable transmit complete interrupt. */
- sbi(UCSRnB, TXCIE);
- }
- #endif
- NutExitCritical();
- }
- /*!
- * \brief Carefully disable USART hardware functions.
- */
- static void AvrUsartDisable(void)
- {
- /*
- * Disable USART interrupts.
- */
- NutEnterCritical();
- cbi(UCSRnB, RXCIE);
- cbi(UCSRnB, TXCIE);
- cbi(UCSRnB, UDRIE);
- NutExitCritical();
- /*
- * Allow incoming or outgoing character to finish.
- */
- NutDelay(10);
- /*
- * Disable USART transmit and receive.
- */
- cbi(UCSRnB, RXEN);
- cbi(UCSRnB, TXEN);
- }
- /*!
- * \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 uint32_t AvrUsartGetSpeed(void)
- {
- uint32_t fct;
- uint16_t sv = (uint16_t) inb(UBRRnL);
- #ifdef __AVR_ENHANCED__
- sv |= ((uint16_t) inb(UBRRnH) << 8);
- /* Synchronous mode. */
- if (bit_is_set(UCSRnC, UMSEL)) {
- fct = 2UL;
- }
- /* Double rate mode. */
- else if (bit_is_set(UCSRnA, U2X)) {
- fct = 8UL;
- }
- /* Normal mode. */
- else {
- fct = 16UL;
- }
- #else
- fct = 16UL;
- #endif
- return NutGetCpuClock() / (fct * ((uint32_t) sv + 1UL));
- }
- /*!
- * \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 AvrUsartSetSpeed(uint32_t rate)
- {
- uint16_t sv;
- AvrUsartDisable();
- /*
- * Modified Robert Hildebrand's refined calculation.
- */
- #ifdef __AVR_ENHANCED__
- if (bit_is_clear(UCSRnC, UMSEL)) {
- if (bit_is_set(UCSRnA, U2X)) {
- rate <<= 2;
- } else {
- rate <<= 3;
- }
- }
- #else
- rate <<= 3;
- #endif
- sv = (uint16_t) ((NutGetCpuClock() / rate + 1UL) / 2UL) - 1;
- outb(UBRRnL, (uint8_t) sv);
- #ifdef __AVR_ENHANCED__
- outb(UBRRnH, (uint8_t) (sv >> 8));
- #endif
- AvrUsartEnable();
- 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 uint8_t AvrUsartGetDataBits(void)
- {
- if (bit_is_set(UCSRnB, UCSZ2)) {
- return 9;
- }
- #ifdef __AVR_ENHANCED__
- if (bit_is_set(UCSRnC, UCSZ1)) {
- if (bit_is_set(UCSRnC, UCSZ0)) {
- return 8;
- } else {
- return 7;
- }
- } else if (bit_is_set(UCSRnC, UCSZ0)) {
- return 6;
- }
- return 5;
- #else
- return 8;
- #endif
- }
- /*!
- * \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 AvrUsartSetDataBits(uint8_t bits)
- {
- AvrUsartDisable();
- cbi(UCSRnB, UCSZ2);
- #ifdef __AVR_ENHANCED__
- cbi(UCSRnC, UCSZ0);
- cbi(UCSRnC, UCSZ1);
- switch (bits) {
- case 6:
- sbi(UCSRnC, UCSZ0);
- break;
- case 9:
- sbi(UCSRnB, UCSZ2);
- case 8:
- sbi(UCSRnC, UCSZ0);
- case 7:
- sbi(UCSRnC, UCSZ1);
- break;
- }
- #else
- if(bits == 9) {
- sbi(UCSRnB, UCSZ2);
- }
- #endif
- AvrUsartEnable();
- /*
- * Verify the result.
- */
- if (AvrUsartGetDataBits() != 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) or 2 (even).
- */
- static uint8_t AvrUsartGetParity(void)
- {
- #ifdef __AVR_ENHANCED__
- if (bit_is_set(UCSRnC, UPM1)) {
- if (bit_is_set(UCSRnC, UPM0)) {
- return 1;
- } else {
- return 2;
- }
- }
- #endif
- return 0;
- }
- /*!
- * \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.
- *
- * \param mode 0 (disabled), 1 (odd) or 2 (even)
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartSetParity(uint8_t mode)
- {
- #ifdef __AVR_ENHANCED__
- AvrUsartDisable();
- switch (mode) {
- case 0:
- cbi(UCSRnC, UPM0);
- cbi(UCSRnC, UPM1);
- break;
- case 1:
- sbi(UCSRnC, UPM0);
- sbi(UCSRnC, UPM1);
- break;
- case 2:
- cbi(UCSRnC, UPM0);
- sbi(UCSRnC, UPM1);
- break;
- }
- AvrUsartEnable();
- #endif
- /*
- * Verify the result.
- */
- if (AvrUsartGetParity() != mode) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Query the USART hardware for the number of stop bits.
- *
- * This routine is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \return The number of stop bits set, either 1 or 2.
- */
- static uint8_t AvrUsartGetStopBits(void)
- {
- #ifdef __AVR_ENHANCED__
- if (bit_is_set(UCSRnC, USBS)) {
- return 2;
- }
- #endif
- return 1;
- }
- /*!
- * \brief Set the USART hardware to the number of stop bits.
- *
- * This routine is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartSetStopBits(uint8_t bits)
- {
- #ifdef __AVR_ENHANCED__
- AvrUsartDisable();
- if (bits == 1) {
- cbi(UCSRnC, USBS);
- } else if (bits == 2) {
- sbi(UCSRnC, USBS);
- }
- AvrUsartEnable();
- #endif
- /*
- * Verify the result.
- */
- if (AvrUsartGetStopBits() != bits) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Query the USART hardware status.
- *
- * \return Status flags.
- */
- static uint32_t AvrUsartGetStatus(void)
- {
- uint32_t rc = 0;
- /*
- * Set receiver error flags.
- */
- if ((rx_errors & _BV(FE)) != 0) {
- rc |= UART_FRAMINGERROR;
- }
- if ((rx_errors & _BV(DOR)) != 0) {
- rc |= UART_OVERRUNERROR;
- }
- #ifdef __AVR_ENHANCED__
- if ((rx_errors & _BV(UPE)) != 0) {
- rc |= UART_PARITYERROR;
- }
- #endif
- /*
- * Determine software handshake status. The flow control status may
- * change during interrupt, but this doesn't really hurt us.
- */
- if (flow_control) {
- if (flow_control & XOFF_SENT) {
- rc |= UART_RXDISABLED;
- }
- if (flow_control & XOFF_RCVD) {
- rc |= UART_TXDISABLED;
- }
- }
- #ifdef UART_RTS_BIT
- /*
- * Determine hardware handshake control status.
- */
- if (bit_is_set(UART_RTS_PORT, UART_RTS_BIT)) {
- rc |= UART_RTSDISABLED;
- if (rts_control) {
- rc |= UART_TXDISABLED;
- }
- } else {
- rc |= UART_RTSENABLED;
- }
- #endif
- #ifdef UART_CTS_BIT
- /*
- * Determine hardware handshake sense status.
- */
- if (bit_is_set(UART_CTS_PIN, UART_CTS_BIT)) {
- rc |= UART_CTSDISABLED;
- if (cts_sense) {
- rc |= UART_RXDISABLED;
- }
- } else {
- rc |= UART_CTSENABLED;
- }
- #endif
- #ifdef UART_DTR_BIT
- /*
- * Determine DTS status.
- */
- if ( bit_is_set( UART_DTR_PORT, UART_DTR_BIT ) ) {
- rc |= UART_DTRENABLED;
- } else {
- rc |= UART_DTRDISABLED;
- }
- #endif
- /*
- * If transmitter and receiver haven't been detected disabled by any
- * of the checks above, then they are probably enabled.
- */
- if ((rc & UART_RXDISABLED) == 0) {
- rc |= UART_RXENABLED;
- }
- if ((rc & UART_TXDISABLED) == 0) {
- rc |= UART_TXENABLED;
- }
- /*
- * Process multidrop setting.
- */
- if (tx_aframe) {
- rc |= UART_TXADDRFRAME;
- } else {
- rc |= UART_TXNORMFRAME;
- }
- #ifdef __AVR_ENHANCED__
- if (bit_is_set(UCSRnA, MPCM)) {
- rc |= UART_RXADDRFRAME;
- } else {
- rc |= UART_RXNORMFRAME;
- }
- #else
- rc |= UART_RXNORMFRAME;
- #endif
- return rc;
- }
- /*!
- * \brief Set the USART hardware status.
- *
- * \param flags Status flags.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartSetStatus(uint32_t flags)
- {
- /*
- * Process software handshake control.
- */
- if (flow_control) {
- /* Access to the flow control status must be atomic. */
- NutEnterCritical();
- /*
- * Enabling or disabling the receiver means to behave like
- * having sent a XON or XOFF character resp.
- */
- if (flags & UART_RXENABLED) {
- flow_control &= ~XOFF_SENT;
- } else if (flags & UART_RXDISABLED) {
- flow_control |= XOFF_SENT;
- }
- /*
- * Enabling or disabling the transmitter means to behave like
- * having received a XON or XOFF character resp.
- */
- if (flags & UART_TXENABLED) {
- flow_control &= ~XOFF_RCVD;
- } else if (flags & UART_TXDISABLED) {
- flow_control |= XOFF_RCVD;
- }
- NutExitCritical();
- }
- #ifdef UART_RTS_BIT
- /*
- * Process hardware handshake control.
- */
- if (rts_control) {
- if (flags & UART_RXDISABLED) {
- sbi(UART_RTS_PORT, UART_RTS_BIT);
- }
- if (flags & UART_RXENABLED) {
- cbi(UART_RTS_PORT, UART_RTS_BIT);
- }
- }
- if (flags & UART_RTSDISABLED) {
- sbi(UART_RTS_PORT, UART_RTS_BIT);
- }
- if (flags & UART_RTSENABLED) {
- cbi(UART_RTS_PORT, UART_RTS_BIT);
- }
- #endif
- #ifdef UART_DTR_BIT
- if ( flags & UART_DTRDISABLED ) {
- sbi(UART_DTR_DDR, UART_DTR_BIT);
- sbi(UART_DTR_PORT, UART_DTR_BIT);
- }
- if ( flags & UART_DTRENABLED ) {
- sbi(UART_DTR_DDR, UART_DTR_BIT);
- cbi(UART_DTR_PORT, UART_DTR_BIT);
- }
- #endif
- /*
- * Process multidrop setting.
- */
- if (flags & UART_TXADDRFRAME) {
- tx_aframe = 1;
- }
- if (flags & UART_TXNORMFRAME) {
- tx_aframe = 0;
- }
- #ifdef __AVR_ENHANCED__
- if (flags & UART_RXADDRFRAME) {
- sbi(UCSRnA, MPCM);
- }
- if (flags & UART_RXNORMFRAME) {
- cbi(UCSRnA, MPCM);
- }
- #endif
- /*
- * Clear UART receive errors.
- */
- if (flags & UART_FRAMINGERROR) {
- rx_errors &= ~_BV(FE);
- }
- if (flags & UART_OVERRUNERROR) {
- rx_errors &= ~_BV(DOR);
- }
- #ifdef __AVR_ENHANCED__
- if (flags & UART_PARITYERROR) {
- rx_errors &= ~_BV(UPE);
- }
- #endif
- /*
- * Verify the result.
- */
- if ((AvrUsartGetStatus() & ~UART_ERRORS) != flags) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Query the USART hardware for synchronous mode.
- *
- * This function is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \return Or-ed combination of \ref UART_SYNC, \ref UART_MASTER,
- * \ref UART_NCLOCK and \ref UART_HIGHSPEED.
- */
- static uint8_t AvrUsartGetClockMode(void)
- {
- uint8_t rc = 0;
- #ifdef __AVR_ENHANCED__
- if (bit_is_set(UCSRnC, UMSEL)) {
- rc |= UART_SYNC;
- if (bit_is_set(DDRE, 2)) {
- rc |= UART_MASTER;
- }
- if (bit_is_set(UCSRnC, UCPOL)) {
- rc |= UART_NCLOCK;
- }
- } else if (bit_is_set(UCSRnA, U2X)) {
- rc |= UART_HIGHSPEED;
- }
- #endif
- return rc;
- }
- /*!
- * \brief Set asynchronous or synchronous mode.
- *
- * This function is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \param mode Must be an or-ed combination of USART_SYNC, USART_MASTER,
- * USART_NCLOCK and USART_HIGHSPEED.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartSetClockMode(uint8_t mode)
- {
- #ifdef __AVR_ENHANCED__
- AvrUsartDisable();
- /*
- * Handle synchronous mode.
- */
- if (mode & UART_SYNC) {
- if (mode & UART_MASTER) {
- /* Enable master mode. */
- sbi(DDRE, 2);
- } else {
- /* Disable master mode. */
- cbi(DDRE, 2);
- }
- if (mode & UART_NCLOCK) {
- /* Enable negated clock. */
- sbi(UCSRnC, UCPOL);
- } else {
- /* Disable negated clock. */
- cbi(UCSRnC, UCPOL);
- }
- /* Disable high speed. */
- cbi(UCSRnA, U2X);
- /* Enable synchronous mode. */
- sbi(UCSRnC, UMSEL);
- }
- /*
- * Handle asynchronous mode.
- */
- else {
- if (mode & UART_HIGHSPEED) {
- /* Enable high speed. */
- sbi(UCSRnA, U2X);
- } else {
- /* Disable high speed. */
- cbi(UCSRnA, U2X);
- }
- /* Disable negated clock. */
- cbi(UCSRnC, UCPOL);
- /* Disable synchronous mode. */
- cbi(UCSRnC, UMSEL);
- }
- AvrUsartEnable();
- #endif
- /*
- * Verify the result.
- */
- if (AvrUsartGetClockMode() != mode) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Query flow control mode.
- *
- * This routine is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \return See UsartIOCtl().
- */
- static uint32_t AvrUsartGetFlowControl(void)
- {
- uint32_t rc = 0;
- if (flow_control) {
- rc |= USART_MF_XONXOFF;
- } else {
- rc &= ~USART_MF_XONXOFF;
- }
- #ifdef UART_RTS_BIT
- if (rts_control) {
- rc |= USART_MF_RTSCONTROL;
- } else {
- rc &= ~USART_MF_RTSCONTROL;
- }
- #endif
- #ifdef UART_CTS_BIT
- if (cts_sense) {
- rc |= USART_MF_CTSSENSE;
- } else {
- rc &= ~USART_MF_CTSSENSE;
- }
- #endif
- #ifdef UART_HDX_BIT
- if (hdx_control) {
- rc |= USART_MF_HALFDUPLEX;
- } else {
- rc &= ~USART_MF_HALFDUPLEX;
- }
- #endif
- return rc;
- }
- /*!
- * \brief Set flow control mode.
- *
- * This function is called by ioctl function of the upper level USART
- * driver through the USARTDCB jump table.
- *
- * \param flags See UsartIOCtl().
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartSetFlowControl(uint32_t flags)
- {
- /*
- * Set software handshake mode.
- */
- if (flags & USART_MF_XONXOFF) {
- if(flow_control == 0) {
- NutEnterCritical();
- flow_control = 1 | XOFF_SENT; /* force XON to be sent on next read */
- NutExitCritical();
- }
- } else {
- NutEnterCritical();
- flow_control = 0;
- NutExitCritical();
- }
- #ifdef UART_RTS_BIT
- /*
- * Set RTS control mode.
- */
- if (flags & USART_MF_RTSCONTROL) {
- sbi(UART_RTS_PORT, UART_RTS_BIT);
- sbi(UART_RTS_DDR, UART_RTS_BIT);
- rts_control = 1;
- } else if (rts_control) {
- rts_control = 0;
- cbi(UART_RTS_DDR, UART_RTS_BIT);
- }
- #endif
- #ifdef UART_CTS_BIT
- /*
- * Set CTS sense mode.
- */
- if (flags & USART_MF_CTSSENSE) {
- /* Register CTS sense interrupt. */
- if (NutRegisterIrqHandler(&UART_CTS_SIGNAL, AvrUsartCts, 0)) {
- return -1;
- }
- sbi(UART_CTS_PORT, UART_CTS_BIT);
- cbi(UART_CTS_DDR, UART_CTS_BIT);
- cts_sense = 1;
- } else if (cts_sense) {
- cts_sense = 0;
- /* Deregister CTS sense interrupt. */
- NutRegisterIrqHandler(&UART_CTS_SIGNAL, 0, 0);
- cbi(UART_CTS_DDR, UART_CTS_BIT);
- }
- #endif
- #ifdef UART_HDX_BIT
- /*
- * Set half duplex mode.
- */
- if (flags & USART_MF_HALFDUPLEX) {
- /* Register transmit complete interrupt. */
- if (NutRegisterIrqHandler(&sig_UART_TRANS, AvrUsartTxComplete, &dcb_usart.dcb_tx_rbf)) {
- return -1;
- }
- /* Initially enable the receiver. */
- UART_HDX_RX(UART_HDX_PORT, UART_HDX_BIT);
- sbi(UART_HDX_DDR, UART_HDX_BIT);
- hdx_control = 1;
- /* Enable transmit complete interrupt. */
- sbi(UCSRnB, TXCIE);
- } else if (hdx_control) {
- hdx_control = 0;
- /* disable transmit complete interrupt */
- cbi(UCSRnB, TXCIE);
- /* Deregister transmit complete interrupt. */
- NutRegisterIrqHandler(&sig_UART_TRANS, 0, 0);
- cbi(UART_HDX_DDR, UART_HDX_BIT);
- }
- #endif
- /*
- * Verify the result.
- */
- if (AvrUsartGetFlowControl() != flags) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Start the USART transmitter hardware.
- *
- * The upper level USART driver will call this function through the
- * USARTDCB jump table each time it added one or more bytes to the
- * transmit buffer.
- */
- static void AvrUsartTxStart(void)
- {
- #ifdef UART_HDX_BIT
- if (hdx_control) {
- /* Enable half duplex transmitter. */
- UART_HDX_TX(UART_HDX_PORT, UART_HDX_BIT);
- }
- #endif
- /* Enable transmit interrupts. */
- sbi(UCSRnB, UDRIE);
- }
- /*!
- * \brief Start the USART receiver hardware.
- *
- * The upper level USART driver will call this function through the
- * USARTDCB jump table each time it removed enough bytes from the
- * receive buffer. Enough means, that the number of bytes left in
- * the buffer is below the low watermark.
- */
- static void AvrUsartRxStart(void)
- {
- /*
- * Do any required software flow control.
- */
- if (flow_control && (flow_control & XOFF_SENT) != 0) {
- NutEnterCritical();
- if (inb(UCSRnA) & _BV(UDRE)) {
- outb(UDRn, ASCII_XON);
- flow_control &= ~XON_PENDING;
- } else {
- flow_control |= XON_PENDING;
- }
- flow_control &= ~(XOFF_SENT | XOFF_PENDING);
- NutExitCritical();
- }
- #ifdef UART_RTS_BIT
- if (rts_control) {
- /* Enable RTS. */
- cbi(UART_RTS_PORT, UART_RTS_BIT);
- }
- #endif
- }
- /*
- * \brief Initialize the USART hardware driver.
- *
- * This function is called during device registration by the upper level
- * USART driver through the USARTDCB jump table.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartInit(void)
- {
- #ifndef USE_USART
- /*
- * Register receive and transmit interrupts.
- */
- if (NutRegisterIrqHandler(&sig_UART_RECV, AvrUsartRxComplete, &dcb_usart.dcb_rx_rbf))
- return -1;
- if (NutRegisterIrqHandler(&sig_UART_DATA, AvrUsartTxEmpty, &dcb_usart.dcb_tx_rbf)) {
- NutRegisterIrqHandler(&sig_UART_RECV, 0, 0);
- return -1;
- }
- #endif
- #ifdef UART_RTS_BIT
- sbi(UART_RTS_DDR, UART_RTS_BIT);
- #endif
- #ifdef UART_DTR_BIT
- sbi(UART_DTR_DDR, UART_DTR_BIT);
- #endif
- return 0;
- }
- /*
- * \brief Deinitialize the USART hardware driver.
- *
- * This function is called during device deregistration by the upper
- * level USART driver through the USARTDCB jump table.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AvrUsartDeinit(void)
- {
- #ifndef USE_USART
- /* Deregister receive and transmit interrupts. */
- NutRegisterIrqHandler(&sig_UART_RECV, 0, 0);
- NutRegisterIrqHandler(&sig_UART_DATA, 0, 0);
- #endif
- /*
- * Disabling flow control shouldn't be required here, because it's up
- * to the upper level to do this on the last close or during
- * deregistration.
- */
- #ifdef UART_HDX_BIT
- /* Deregister transmit complete interrupt. */
- if (hdx_control) {
- hdx_control = 0;
- NutRegisterIrqHandler(&sig_UART_TRANS, 0, 0);
- }
- #endif
- #ifdef UART_CTS_BIT
- if (cts_sense) {
- cts_sense = 0;
- cbi(UART_CTS_DDR, UART_CTS_BIT);
- /* Deregister CTS sense interrupt. */
- NutRegisterIrqHandler(&UART_CTS_SIGNAL, 0, 0);
- }
- #endif
- #ifdef UART_RTS_BIT
- if (rts_control) {
- rts_control = 0;
- cbi(UART_RTS_DDR, UART_RTS_BIT);
- }
- #endif
- #ifdef UART_DTR_BIT
- cbi(UART_DTR_DDR, UART_DTR_BIT);
- #endif
- return 0;
- }
- /*@}*/
|