From d12df2eed3650e16dc4281eaa58d2b4402e1c534 Mon Sep 17 00:00:00 2001 From: Mariano Alvira Date: Wed, 24 Oct 2012 14:54:24 -0400 Subject: [PATCH] use rx and tx queues for uart --- lib/include/uart.h | 35 +++++++++++++- lib/uart.c | 43 ++++++++++++----- lib/uart1.c | 104 ++++++++++++++++++++++++++++++++++------- lib/uart2.c | 100 ++++++++++++++++++++++++++++++++------- src/default_lowlevel.c | 67 -------------------------- 5 files changed, 235 insertions(+), 114 deletions(-) diff --git a/lib/include/uart.h b/lib/include/uart.h index 222b7a54d..353c24ca7 100644 --- a/lib/include/uart.h +++ b/lib/include/uart.h @@ -156,14 +156,45 @@ void uart_init(volatile struct UART_struct * uart, uint32_t baud); void uart_setbaud(volatile struct UART_struct * uart, uint32_t baud); void uart_flowctl(volatile struct UART_struct * uart, uint8_t on); -extern volatile uint32_t u1_head, u1_tail; + +/* The mc1322x has a 32 byte hardware FIFO for transmitted characters. + * Currently it is always filled from a larger RAM buffer. It would be + * possible to eliminate that overhead by filling directly from a chain + * of data buffer pointers, but printf's would be not so easy. + */ +#define UART1_TX_BUFFERSIZE 1024 +extern volatile uint32_t u1_tx_head, u1_tx_tail; void uart1_putc(char c); + +/* The mc1322x has a 32 byte hardware FIFO for received characters. + * If a larger rx buffersize is specified the FIFO will be extended into RAM. + * RAM transfers will occur on interrupt when the FIFO is nearly full. + * If a smaller buffersize is specified hardware flow control will be + * initiated at that FIFO level. + * Set to 32 for no flow control or RAM buffer. + */ +#define UART1_RX_BUFFERSIZE 128 +#if UART1_RX_BUFFERSIZE > 32 +extern volatile uint32_t u1_rx_head, u1_rx_tail; +#define uart1_can_get() ((u1_rx_head!=u1_rx_tail) || (*UART1_URXCON > 0)) +#else #define uart1_can_get() (*UART1_URXCON > 0) +#endif uint8_t uart1_getc(void); -extern volatile uint32_t u2_head, u2_tail; + +#define UART2_TX_BUFFERSIZE 1024 +extern volatile uint32_t u2_tx_head, u2_tx_tail; void uart2_putc(char c); + +#define UART2_RX_BUFFERSIZE 128 +#if UART2_RX_BUFFERSIZE > 32 +extern volatile uint32_t u2_rx_head, u2_rx_tail; +#define uart2_can_get() ((u2_rx_head!=u2_rx_tail) || (*UART2_URXCON > 0)) +#else #define uart2_can_get() (*UART2_URXCON > 0) +#endif uint8_t uart2_getc(void); #endif + diff --git a/lib/uart.c b/lib/uart.c index 3dc24688b..d56735901 100644 --- a/lib/uart.c +++ b/lib/uart.c @@ -50,18 +50,14 @@ void uart_setbaud(volatile struct UART_struct * uart, uint32_t baud) { inc = (inc + 5) / 10; /* UART must be disabled to set the baudrate */ - uart->CONbits = (struct UART_CON) { - .TXE = 0, - .RXE = 0, - }; + uart->CONbits.TXE = 0; + uart->CONbits.RXE = 0; uart->BR = ( (uint16_t)inc << 16 ) | MOD; - uart->CONbits = (struct UART_CON) { - .XTIM = 0, - .TXE = 1, - .RXE = 1, - }; + uart->CONbits.XTIM = 0; + uart->CONbits.TXE = 1; + uart->CONbits.RXE = 1; } void uart_flowctl(volatile struct UART_struct * uart, uint8_t on) { @@ -117,6 +113,7 @@ void uart_init(volatile struct UART_struct * uart, uint32_t baud) { .TXE = 1, .RXE = 1, }; + /* interrupt when there are this number or more bytes free in the TX buffer*/ uart->TXCON = 16; @@ -129,7 +126,19 @@ void uart_init(volatile struct UART_struct * uart, uint32_t baud) { GPIO->FUNC_SEL.U1TX = 1; GPIO->FUNC_SEL.U1RX = 1; - u1_head = 0; u1_tail = 0; +#if UART1_RX_BUFFERSIZE > 32 + *UART1_UCON = (1 << 0) | (1 << 1) ; /* enable receive, transmit, and both interrupts */ + *UART1_URXCON = 30; /* interrupt when fifo is nearly full */ + u1_rx_head = 0; u1_rx_tail = 0; +#elif UART1_RX_BUFFERSIZE < 32 /* enable receive, transmit, flow control, disable rx interrupt */ + *UART1_UCON = (1 << 0) | (1 << 1) | (1 << 12) | (1 << 14); + *UART1_UCTS = UART1_RX_BUFFERSIZE; /* drop cts when tx buffer at trigger level */ + *GPIO_FUNC_SEL1 = ( (0x01 << (0*2)) | (0x01 << (1*2)) ); /* set GPIO17-16 to UART1 CTS and RTS */ +#else + *UART1_UCON = (1 << 0) | (1 << 1) | (1 << 14); /* enable receive, transmit, disable rx interrupt */ +#endif + + u1_tx_head = 0; u1_tx_tail = 0; /* tx and rx interrupts are enabled in the UART by default */ /* see status register bits 13 and 14 */ @@ -146,7 +155,19 @@ void uart_init(volatile struct UART_struct * uart, uint32_t baud) { GPIO->FUNC_SEL.U2TX = 1; GPIO->FUNC_SEL.U2RX = 1; - u2_head = 0; u2_tail = 0; +#if UART2_RX_BUFFERSIZE > 32 + *UART2_UCON = (1 << 0) | (1 << 1) ; /* enable receive, transmit, and both interrupts */ + *UART2_URXCON = 30; /* interrupt when fifo is nearly full */ + u2_rx_head = 0; u2_rx_tail = 0; +#elif UART2_RX_BUFFERSIZE < 32 /* enable receive, transmit, disable flow control, disable rx interrupt */ + *UART2_UCON = (1 << 0) | (1 << 1) | (0 << 12) | (1 << 14); + *UART2_UCTS = UART2_RX_BUFFERSIZE; /* drop cts when tx buffer at trigger level */ + *GPIO_FUNC_SEL1 = ( (0x01 << (0*2)) | (0x01 << (1*2)) ); /* set GPIO17-16 to UART2 CTS and RTS */ +#else + *UART2_UCON = (1 << 0) | (1 << 1) | (1 << 14); /* enable receive, transmit, disable rx interrupt */ +#endif + + u2_tx_head = 0; u2_tx_tail = 0; enable_irq(UART2); } diff --git a/lib/uart1.c b/lib/uart1.c index 2dc0a9c51..f45ccbeae 100644 --- a/lib/uart1.c +++ b/lib/uart1.c @@ -28,7 +28,7 @@ * SUCH DAMAGE. * * This file is part of libmc1322x: see http://mc1322x.devl.org - * for details. + * for details. * * */ @@ -36,43 +36,111 @@ #include #include -volatile char u1_tx_buf[64]; -volatile uint32_t u1_head, u1_tail; +volatile char u1_tx_buf[UART1_TX_BUFFERSIZE]; +volatile uint32_t u1_tx_head, u1_tx_tail; + +#if UART1_RX_BUFFERSIZE > 32 +volatile char u1_rx_buf[UART1_RX_BUFFERSIZE-32]; +volatile uint32_t u1_rx_head, u1_rx_tail; +#endif void uart1_isr(void) { - while( *UART1_UTXCON != 0 ) { - if (u1_head == u1_tail) { + +#if UART1_RX_BUFFERSIZE > 32 + if (*UART1_USTAT & ( 1 << 6)) { //receive interrupt + while( *UART1_URXCON != 0 ) { //flush the hardware fifo into the software buffer + uint32_t u1_rx_tail_next; + u1_rx_tail_next = u1_rx_tail+1; + if (u1_rx_tail_next >= sizeof(u1_rx_buf)) + u1_rx_tail_next = 0; + if (u1_rx_head != u1_rx_tail_next) { + u1_rx_buf[u1_rx_tail]= *UART1_UDATA; + u1_rx_tail = u1_rx_tail_next; + } else { //buffer is full, flush the fifo + while (*UART1_URXCON !=0) { if (*UART1_UDATA) { } } + } + } + return; + } +#endif + + while( *UART1_UTXCON != 0 ) { + if (u1_tx_head == u1_tx_tail) { +#if UART1_RX_BUFFERSIZE > 32 + *UART1_UCON |= (1 << 13); /*disable tx interrupt */ +#else disable_irq(UART1); +#endif return; } - *UART1_UDATA = u1_tx_buf[u1_tail]; - u1_tail++; - if (u1_tail >= sizeof(u1_tx_buf)) - u1_tail = 0; + + *UART1_UDATA = u1_tx_buf[u1_tx_tail]; + u1_tx_tail++; + if (u1_tx_tail >= sizeof(u1_tx_buf)) + u1_tx_tail = 0; } } void uart1_putc(char c) { /* disable UART1 since */ - /* UART1 isr modifies u1_head and u1_tail */ - disable_irq(UART1); + /* UART1 isr modifies u1_tx_head and u1_tx_tail */ +#if UART1_RX_BUFFERSIZE > 32 + *UART1_UCON |= (1 << 13); /*disable tx interrupt */ +#else + disable_irq(UART1); +#endif - if( (u1_head == u1_tail) && + if( (u1_tx_head == u1_tx_tail) && (*UART1_UTXCON != 0)) { *UART1_UDATA = c; } else { - u1_tx_buf[u1_head] = c; - u1_head += 1; - if (u1_head >= sizeof(u1_tx_buf)) - u1_head = 0; - if (u1_head == u1_tail) { /* drop chars when no room */ - if (u1_head) { u1_head -=1; } else { u1_head = sizeof(u1_tx_buf); } + u1_tx_buf[u1_tx_head] = c; + u1_tx_head += 1; + if (u1_tx_head >= sizeof(u1_tx_buf)) + u1_tx_head = 0; + if (u1_tx_head == u1_tx_tail) { /* drop chars when no room */ +#if UART1_DROP_CHARS + if (u1_tx_head) { u1_tx_head -=1; } else { u1_tx_head = sizeof(u1_tx_buf); } +#else + { + uint32_t u1_tx_tail_save=u1_tx_tail; + /* Back up head to show buffer not empty, and enable tx interrupt */ + u1_tx_head--; +#if UART1_RX_BUFFERSIZE > 32 + *UART1_UCON &= ~(1 << 13); /*enable tx interrupt */ +#else + enable_irq(UART1); +#endif + /* Tail will change after one character goes out */ + while (u1_tx_tail_save == u1_tx_tail) ; + /* Restore head to character we just stuffed */ + u1_tx_head++; + return; + } +#endif /* UART1_DROP_CHARS */ } + +#if UART1_RX_BUFFERSIZE > 32 + *UART1_UCON &= ~(1 << 13); /*enable tx interrupt */ +#else enable_irq(UART1); +#endif + } } uint8_t uart1_getc(void) { +#if UART1_RX_BUFFERSIZE > 32 +/* First pull from the ram buffer */ +uint8_t c=0; + if (u1_rx_head != u1_rx_tail) { + c = u1_rx_buf[u1_rx_head++]; + if (u1_rx_head >= sizeof(u1_rx_buf)) + u1_rx_head=0; + return c; + } +#endif +/* Then pull from the hardware fifo */ while(uart1_can_get() == 0) { continue; } return *UART1_UDATA; } diff --git a/lib/uart2.c b/lib/uart2.c index 96ea8d30f..b5b2f22de 100644 --- a/lib/uart2.c +++ b/lib/uart2.c @@ -36,43 +36,111 @@ #include #include -volatile char u2_tx_buf[64]; -volatile uint32_t u2_head, u2_tail; +volatile char u2_tx_buf[UART2_TX_BUFFERSIZE]; +volatile uint32_t u2_tx_head, u2_tx_tail; + +#if UART2_RX_BUFFERSIZE > 32 +volatile char u2_rx_buf[UART2_RX_BUFFERSIZE-32]; +volatile uint32_t u2_rx_head, u2_rx_tail; +#endif void uart2_isr(void) { + +#if UART2_RX_BUFFERSIZE > 32 + if (*UART2_USTAT & ( 1 << 6)) { //receive interrupt + while( *UART2_URXCON != 0 ) { //flush the hardware fifo into the software buffer + uint32_t u2_rx_tail_next; + u2_rx_tail_next = u2_rx_tail+1; + if (u2_rx_tail_next >= sizeof(u2_rx_buf)) + u2_rx_tail_next = 0; + if (u2_rx_head != u2_rx_tail_next) { + u2_rx_buf[u2_rx_tail]= *UART2_UDATA; + u2_rx_tail = u2_rx_tail_next; + } else { //buffer is full, flush the fifo + while (*UART2_URXCON !=0) { if (*UART2_UDATA) { } } + } + } + return; + } +#endif + while( *UART2_UTXCON != 0 ) { - if (u2_head == u2_tail) { + if (u2_tx_head == u2_tx_tail) { +#if UART2_RX_BUFFERSIZE > 32 + *UART2_UCON |= (1 << 13); /*disable tx interrupt */ +#else disable_irq(UART2); +#endif return; } - *UART2_UDATA = u2_tx_buf[u2_tail]; - u2_tail++; - if (u2_tail >= sizeof(u2_tx_buf)) - u2_tail = 0; + *UART2_UDATA = u2_tx_buf[u2_tx_tail]; + u2_tx_tail++; + if (u2_tx_tail >= sizeof(u2_tx_buf)) + u2_tx_tail = 0; } + } void uart2_putc(char c) { /* disable UART2 since */ - /* UART2 isr modifies u2_head and u2_tail */ - disable_irq(UART2); + /* UART2 isr modifies u2_tx_head and u2_tx_tail */ +#if UART2_RX_BUFFERSIZE > 32 + *UART2_UCON |= (1 << 13); /*disable tx interrupt */ +#else + disable_irq(UART2); +#endif - if( (u2_head == u2_tail) && + if( (u2_tx_head == u2_tx_tail) && (*UART2_UTXCON != 0)) { *UART2_UDATA = c; } else { - u2_tx_buf[u2_head] = c; - u2_head += 1; - if (u2_head >= sizeof(u2_tx_buf)) - u2_head = 0; - if (u2_head == u2_tail) { /* drop chars when no room */ - if (u2_head) { u2_head -=1; } else { u2_head = sizeof(u2_tx_buf); } + u2_tx_buf[u2_tx_head] = c; + u2_tx_head += 1; + if (u2_tx_head >= sizeof(u2_tx_buf)) + u2_tx_head = 0; + if (u2_tx_head == u2_tx_tail) { /* drop chars when no room */ +#if UART2_DROP_CHARS + if (u2_tx_head) { u2_tx_head -=1; } else { u2_tx_head = sizeof(u2_tx_buf); } +#else + { + uint32_t u2_tx_tail_save=u2_tx_tail; + /* Back up head to show buffer not empty, and enable tx interrupt */ + u2_tx_head--; +#if UART2_RX_BUFFERSIZE > 32 + *UART2_UCON &= ~(1 << 13); /*enable tx interrupt */ +#else + enable_irq(UART2); +#endif + /* Tail will change after one character goes out */ + while (u2_tx_tail_save == u2_tx_tail) ; + /* Restore head to character we just stuffed */ + u2_tx_head++; + return; + } +#endif /* UART2_DROP_CHARS */ } + +#if UART2_RX_BUFFERSIZE > 32 + *UART2_UCON &= ~(1 << 13); /*enable tx interrupt */ +#else enable_irq(UART2); +#endif + } } uint8_t uart2_getc(void) { +#if UART2_RX_BUFFERSIZE > 32 +/* First pull from the ram buffer */ +uint8_t c=0; + if (u2_rx_head != u2_rx_tail) { + c = u2_rx_buf[u2_rx_head++]; + if (u2_rx_head >= sizeof(u2_rx_buf)) + u2_rx_head=0; + return c; + } +#endif +/* Then pull from the hardware fifo */ while(uart2_can_get() == 0) { continue; } return *UART2_UDATA; } diff --git a/src/default_lowlevel.c b/src/default_lowlevel.c index 3ade95da8..6150885a0 100644 --- a/src/default_lowlevel.c +++ b/src/default_lowlevel.c @@ -58,70 +58,3 @@ void buck_init(void) { while(CRM->STATUSbits.VREG_1P8V_RDY == 0) { continue; } } -void uart1_init(volatile uint16_t inc, volatile uint16_t mod, volatile uint8_t samp) { - - /* UART must be disabled to set the baudrate */ - UART1->CON = 0; - - UART1->BR = ( inc << 16 ) | mod; - - /* TX and CTS as outputs */ - GPIO->PAD_DIR_SET.GPIO_14 = 1; - GPIO->PAD_DIR_SET.GPIO_16 = 1; - - /* RX and RTS as inputs */ - GPIO->PAD_DIR_RESET.GPIO_15 = 1; - GPIO->PAD_DIR_RESET.GPIO_17 = 1; - - /* see Section 11.5.1.2 Alternate Modes */ - /* you must enable the peripheral first BEFORE setting the function in GPIO_FUNC_SEL */ - /* From the datasheet: "The peripheral function will control operation of the pad IF */ - /* THE PERIPHERAL IS ENABLED. */ - UART1->CON = (1 << 0) | (1 << 1); /* enable receive, transmit */ - if(samp == UCON_SAMP_16X) - set_bit(*UART1_UCON,UCON_SAMP); - - /* set GPIO15-14 to UART (UART1 TX and RX)*/ - GPIO->FUNC_SEL.GPIO_14 = 1; - GPIO->FUNC_SEL.GPIO_15 = 1; - - /* interrupt when there are this number or more bytes free in the TX buffer*/ - UART1->TXCON = 16; - - u1_head = 0; u1_tail = 0; - - /* tx and rx interrupts are enabled in the UART by default */ - /* see status register bits 13 and 14 */ - /* enable UART1 interrupts in the interrupt controller */ - enable_irq(UART1); -} - -void uart2_init(volatile uint16_t inc, volatile uint16_t mod, volatile uint8_t samp) { - - /* UART must be disabled to set the baudrate */ - UART2->CON = 0; - UART2->BR = ( inc << 16 ) | mod; - - /* see Section 11.5.1.2 Alternate Modes */ - /* you must enable the peripheral first BEFORE setting the function in GPIO_FUNC_SEL */ - /* From the datasheet: "The peripheral function will control operation of the pad IF */ - /* THE PERIPHERAL IS ENABLED. Can override with U2_ENABLE_DEFAULT. */ - UART2->CON = (1 << 0) | (1 << 1); /* enable receive, transmit */ - - if(samp == UCON_SAMP_16X) - set_bit(*UART2_UCON, samp); - - /* set GPIO18-19 to UART (UART2 TX and RX)*/ - GPIO->FUNC_SEL.GPIO_18 = 1; - GPIO->FUNC_SEL.GPIO_19 = 1; - - /* interrupt when there are this number or more bytes free in the TX buffer*/ - UART2->TXCON = 16; - - u2_head = 0; u2_tail = 0; - - /* tx and rx interrupts are enabled in the UART by default */ - /* see status register bits 13 and 14 */ - /* enable UART2 interrupts in the interrupt controller */ - enable_irq(UART2); -}