| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /*
- * Copyright (C) 2012-2013 by egnite GmbH
- * 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.
- *
- * 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/
- */
- /*!
- * \file arch/avr/usart_cb_avr.c
- * \brief Low level routines for AVR UARTs.
- *
- * See comments in the UART0 driver about constant port addresses.
- * The routines in this file should work for all UARTs. This saves
- * code in applications using multiple UARTs, but adds more code
- * to applications using a single UART only. To avoid the latter,
- * NUT_USE_UART0_ONLY may be defined.
- *
- * \verbatim
- * $Id$
- * \endverbatim
- */
- #include <dev/usart.h>
- #include <sys/timer.h>
- #include <arch/avr/usart_avrctl.h>
- #if defined(UBRR0H)
- #define UBRR0_HIGH ((uint32_t) inb(UBRR0H) << 8)
- #else
- #define UBRR0_HIGH 0
- #endif
- #if defined(U2X0)
- #define U2X0_SET (bit_is_set(UCSR0A, U2X0) != 0)
- #else
- #define U2X0_SET 0
- #endif
- #if defined(UMSEL0)
- #define UMSEL0_SET (bit_is_set(UCSR0C, UMSEL0) != 0)
- #else
- #define UMSEL0_SET 0
- #endif
- #if defined(UBRR1H)
- #define UBRR1_HIGH ((uint32_t) inb(UBRR1H) << 8)
- #else
- #define UBRR1_HIGH 0
- #endif
- #if defined(U2X1)
- #define U2X1_SET (bit_is_set(UCSR1A, U2X1) != 0)
- #else
- #define U2X1_SET 0
- #endif
- #if defined(UMSEL1)
- #define UMSEL1_SET (bit_is_set(UCSR1C, UMSEL1) != 0)
- #else
- #define UMSEL1_SET 0
- #endif
- #if defined(UBRR2H)
- #define UBRR2_HIGH ((uint32_t) inb(UBRR2H) << 8)
- #else
- #define UBRR2_HIGH 0
- #endif
- #if defined(U2X2)
- #define U2X2_SET (bit_is_set(UCSR2A, U2X2) != 0)
- #else
- #define U2X2_SET 0
- #endif
- #if defined(UMSEL2)
- #define UMSEL2_SET (bit_is_set(UCSR2C, UMSEL2) != 0)
- #else
- #define UMSEL2_SET 0
- #endif
- #if defined(UBRR3H)
- #define UBRR3_HIGH ((uint32_t) inb(UBRR3H) << 8)
- #else
- #define UBRR3_HIGH 0
- #endif
- #if defined(U2X3)
- #define U2X3_SET (bit_is_set(UCSR3A, U2X3) != 0)
- #else
- #define U2X3_SET 0
- #endif
- #if defined(UMSEL3)
- #define UMSEL3_SET (bit_is_set(UCSR3C, UMSEL3) != 0)
- #else
- #define UMSEL3_SET 0
- #endif
- static uint32_t UsartGetSpeed(uint8_t ifn)
- {
- uint32_t div;
- #if !defined(NUT_USE_UART0_ONLY)
- uint8_t shift;
- switch (ifn) {
- case 0:
- div = inb(UBRR0L) | UBRR0_HIGH;
- shift = (UMSEL0_SET ? 0 : 4 - U2X0_SET);
- break;
- case 1:
- div = inb(UBRR1L) | UBRR1_HIGH;
- shift = (UMSEL1_SET ? 0 : 4 - U2X1_SET);
- break;
- #if defined(UBRR2L)
- /* USART2 --------------------- */
- case 2:
- div = inb(UBRR2L) | UBRR2_HIGH;
- shift = (UMSEL2_SET ? 0 : 4 - U2X2_SET);
- break;
- #if defined(UBRR3L)
- /* USART3 --------------------- */
- case 3:
- div = inb(UBRR3L) | UBRR3_HIGH;
- shift = (UMSEL3_SET ? 0 : 4 - U2X3_SET);
- break;
- #endif
- #endif
- default:
- return 0;
- }
- div++;
- div <<= shift;
- #elif defined(NUT_USE_UART0_ONLY)
- div = inb(UBRR0L);
- div |= UBRR0_HIGH;
- div++;
- div <<= (UMSEL0_SET ? 0 : 4 - U2X0_SET);
- #endif
- return NutClockGet(NUT_HWCLK_PERIPHERAL) / div;
- }
- static int UsartSetSpeed(uint8_t ifn, uint32_t rate)
- {
- uint16_t sv;
- #if !defined(NUT_USE_UART0_ONLY)
- uint8_t shift;
- switch (ifn) {
- case 0:
- shift = (UMSEL0_SET ? 0 : 3 - U2X0_SET);
- break;
- case 1:
- shift = (UMSEL1_SET ? 0 : 3 - U2X1_SET);
- break;
- #if defined(UBRR2L)
- case 2:
- shift = (UMSEL2_SET ? 0 : 3 - U2X2_SET);
- break;
- #if defined(UBRR3L)
- case 3:
- shift = (UMSEL3_SET ? 0 : 3 - U2X3_SET);
- break;
- #endif
- #endif
- default:
- return -1;
- }
- rate <<= shift;
- sv = (uint16_t) ((NutClockGet(NUT_HWCLK_PERIPHERAL) / rate + 1UL) / 2UL) - 1;
- switch (ifn) {
- case 0:
- outb(UBRR0L, (uint8_t) sv);
- #if defined(UBRR0H)
- outb(UBRR0H, (uint8_t) (sv >> 8));
- #endif
- break;
- case 1:
- outb(UBRR1L, (uint8_t) sv);
- #if defined(UBRR1H)
- outb(UBRR1H, (uint8_t) (sv >> 8));
- #endif
- break;
- #if defined(UBRR2L)
- case 2:
- outb(UBRR2L, (uint8_t) sv);
- #if defined(UBRR2H)
- outb(UBRR2H, (uint8_t) (sv >> 8));
- #endif
- break;
- #if defined(UBRR3L)
- case 3:
- outb(UBRR3L, (uint8_t) sv);
- #if defined(UBRR3H)
- outb(UBRR3H, (uint8_t) (sv >> 8));
- #endif
- break;
- #endif
- #endif
- }
- #else
- if (bit_is_clear(UCSR0C, UMSEL)) {
- if (bit_is_set(UCSR0A, U2X)) {
- rate <<= 2;
- } else {
- rate <<= 3;
- }
- }
- #endif
- return 0;
- }
- static uint_fast8_t UsartGetDataBits(uint8_t ifn)
- {
- #if !defined(NUT_USE_UART0_ONLY)
- uint_fast8_t szn2 = 0;
- uint_fast8_t src = 0;
- switch (ifn) {
- case 0:
- szn2 = bit_is_set(UCSR0B, UCSZ02) != 0;
- src = inb(UCSR0C);
- break;
- case 1:
- szn2 = bit_is_set(UCSR1B, UCSZ12) != 0;
- src = inb(UCSR1C);
- break;
- #ifdef UCSR2C
- case 2:
- szn2 = bit_is_set(UCSR2B, UCSZ22) != 0;
- src = inb(UCSR2C);
- break;
- #ifdef UCSR3C
- case 3:
- szn2 = bit_is_set(UCSR3B, UCSZ32) != 0;
- src = inb(UCSR3C);
- break;
- #endif
- #endif
- }
- return szn2 ? 9 : ((src & 0x06) >> 1) + 5;
- #else
- if (bit_is_set(UCSR0B, UCSZ02)) {
- return 9;
- }
- return ((inb(UCSR0C) & 0x06) >> 1) + 5;
- #endif
- }
- static int UsartSetDataBits(uint8_t ifn, uint_fast8_t bits)
- {
- if (bits == 9) {
- switch (ifn) {
- case 0:
- sbi(UCSR0B, UCSZ02);
- break;
- case 1:
- sbi(UCSR1B, UCSZ12);
- break;
- #ifdef UCSZ22
- case 2:
- sbi(UCSR2B, UCSZ22);
- break;
- #ifdef UCSZ32
- case 3:
- sbi(UCSR3B, UCSZ32);
- break;
- #endif
- #endif
- default:
- return -1;
- }
- bits = 5;
- }
- if (bits >= 5 && bits <= 8) {
- bits = (bits - 5) << 1;
- switch (ifn) {
- case 0:
- outb(UCSR0C, (inb(UCSR0C) & ~(_BV(UCSZ00) | _BV(UCSZ01))) | bits);
- break;
- case 1:
- outb(UCSR1C, (inb(UCSR1C) & ~(_BV(UCSZ10) | _BV(UCSZ11))) | bits);
- break;
- #if defined(UCSZ20) && defined(UCSZ21)
- case 2:
- outb(UCSR2C, (inb(UCSR2C) & ~(_BV(UCSZ20) | _BV(UCSZ21))) | bits);
- break;
- #if defined(UCSZ30) && defined(UCSZ31)
- case 3:
- outb(UCSR3C, (inb(UCSR3C) & ~(_BV(UCSZ30) | _BV(UCSZ31))) | bits);
- break;
- #endif
- #endif
- default:
- return -1;
- }
- }
- return 0;
- }
- static uint_fast8_t UsartGetParity(uint8_t ifn)
- {
- uint_fast8_t rc = 0;
- switch (ifn) {
- case 0:
- rc = inb(UCSR0C) & (_BV(UPM00) | _BV(UPM01));
- break;
- case 1:
- rc = inb(UCSR1C) & (_BV(UPM10) | _BV(UPM11));
- break;
- #if defined(UPM20) && defined(UPM21)
- case 2:
- rc = inb(UCSR2C) & (_BV(UPM20) | _BV(UPM21));
- break;
- #if defined(UPM30) && defined(UPM31)
- case 3:
- rc = inb(UCSR3C) & (_BV(UPM30) | _BV(UPM31));
- break;
- #endif
- #endif
- }
- rc >>= 4;
- if (rc == 3) {
- rc = 1;
- }
- return rc;
- }
- static int UsartSetParity(uint8_t ifn, uint_fast8_t mode)
- {
- if (mode <= 2) {
- if (mode == 1) {
- mode = 3;
- }
- mode <<= 4;
- switch (ifn) {
- case 0:
- outb(UCSR0C, (inb(UCSR0C) & ~(_BV(UPM00) | _BV(UPM01))) | mode);
- break;
- case 1:
- outb(UCSR1C, (inb(UCSR1C) & ~(_BV(UPM10) | _BV(UPM11))) | mode);
- break;
- #if defined(UPM20) && defined(UPM21)
- case 2:
- outb(UCSR2C, (inb(UCSR2C) & ~(_BV(UPM20) | _BV(UPM21))) | mode);
- break;
- #if defined(UPM30) && defined(UPM31)
- case 3:
- outb(UCSR3C, (inb(UCSR3C) & ~(_BV(UPM30) | _BV(UPM31))) | mode);
- break;
- #endif
- #endif
- }
- return 0;
- }
- return -1;
- }
- static uint8_t UsartGetStopBits(uint8_t ifn)
- {
- uint8_t rc = 0;
- switch (ifn) {
- case 0:
- rc = bit_is_set(UCSR0C, USBS0) != 0;
- break;
- case 1:
- rc = bit_is_set(UCSR1C, USBS1) != 0;
- break;
- #if defined(USBS2)
- case 2:
- rc = bit_is_set(UCSR2C, USBS2) != 0;
- break;
- #if defined(USBS2)
- case 3:
- rc = bit_is_set(UCSR3C, USBS3) != 0;
- break;
- #endif
- #endif
- }
- return rc + 1;
- }
- static int UsartSetStopBits(uint8_t ifn, uint8_t bits)
- {
- if (bits == 1) {
- switch (ifn) {
- case 0:
- cbi(UCSR0C, USBS0);
- break;
- case 1:
- cbi(UCSR1C, USBS1);
- break;
- #if defined(USBS2)
- case 2:
- cbi(UCSR2C, USBS2);
- break;
- #if defined(USBS3)
- case 3:
- cbi(UCSR3C, USBS3);
- break;
- #endif
- #endif
- default:
- return -1;
- }
- }
- else if (bits == 2) {
- switch (ifn) {
- case 0:
- sbi(UCSR0C, USBS0);
- break;
- case 1:
- sbi(UCSR1C, USBS1);
- break;
- #if defined(USBS2)
- case 2:
- sbi(UCSR2C, USBS2);
- break;
- #if defined(USBS3)
- case 3:
- sbi(UCSR3C, USBS3);
- break;
- #endif
- #endif
- default:
- return -1;
- }
- }
- else {
- return -1;
- }
- return 0;
- }
- int AvrUsartControl(USARTCB_DCB *dcb, int req, void *conf)
- {
- int rc = 0;
- uint32_t *u32vp = (uint32_t *) conf;
- AVRUSART_IFC *uif = (AVRUSART_IFC *) dcb->usart_hwif;
- int8_t ifn = uif->uifc_num;
- switch (req) {
- case UART_GETSPEED:
- *u32vp = UsartGetSpeed(ifn);
- break;
- case UART_SETSPEED:
- rc = UsartSetSpeed(ifn, *u32vp);
- break;
- case UART_GETDATABITS:
- *u32vp = UsartGetDataBits(ifn);
- break;
- case UART_SETDATABITS:
- rc = UsartSetDataBits(ifn, (uint_fast8_t) *u32vp);
- break;
- case UART_GETPARITY:
- *u32vp = UsartGetParity(ifn);
- break;
- case UART_SETPARITY:
- rc = UsartSetParity(ifn, (uint_fast8_t) *u32vp);
- break;
- case UART_GETSTOPBITS:
- *u32vp = UsartGetStopBits(ifn);
- break;
- case UART_SETSTOPBITS:
- rc = UsartSetStopBits(ifn, (uint_fast8_t) *u32vp);
- break;
- case UART_GETSTATUS:
- //*u32vp = dcb->usart_status(dcb, 0);
- break;
- case UART_SETSTATUS:
- //dcb->usart_status(dcb, *u32vp | _BV(31));
- break;
- case UART_GETFLOWCONTROL:
- *u32vp = dcb->usart_mode & (USART_MF_SENSEMASK | USART_MF_CONTROLMASK | USART_MF_XONXOFF);
- break;
- case UART_SETFLOWCONTROL:
- if (*u32vp & ~(dcb->usart_caps & (USART_MF_SENSEMASK | USART_MF_CONTROLMASK | USART_MF_XONXOFF))) {
- rc = -1;
- } else {
- dcb->usart_mode &= ~dcb->usart_caps;
- dcb->usart_mode |= *u32vp;
- }
- break;
- case UART_GETRXBUFLWMARK:
- *u32vp = dcb->usart_rx_lowm;
- break;
- case UART_SETRXBUFLWMARK:
- dcb->usart_rx_lowm = (size_t) *u32vp;
- break;
- case UART_GETRXBUFHWMARK:
- *u32vp = dcb->usart_rx_hiwm;
- break;
- case UART_SETRXBUFHWMARK:
- dcb->usart_rx_hiwm = (size_t) *u32vp;
- break;
- default:
- rc = -1;
- break;
- }
- return rc;
- }
|