diff --git a/cpu/mc1322x/lib/include/uart1.h b/cpu/mc1322x/lib/include/uart1.h index d80eac65d..4e635e930 100644 --- a/cpu/mc1322x/lib/include/uart1.h +++ b/cpu/mc1322x/lib/include/uart1.h @@ -70,9 +70,29 @@ #define UART2_UCTS ((volatile uint32_t *) ( UART2_BASE + UCTS )) #define UART2_UBRCNT ((volatile uint32_t *) ( UART2_BASE + UBRCNT )) -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); diff --git a/cpu/mc1322x/lib/uart1.c b/cpu/mc1322x/lib/uart1.c index 0d3fbd807..b3df668c7 100644 --- a/cpu/mc1322x/lib/uart1.c +++ b/cpu/mc1322x/lib/uart1.c @@ -36,43 +36,91 @@ #include #include -volatile char u1_tx_buf[1024]; -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) { + +#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; + } + } + return; + } +#endif + while( *UART1_UTXCON != 0 ) { - if (u1_head == u1_tail) { + 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 (u1_tx_head) { u1_tx_head -=1; } else { u1_tx_head = sizeof(u1_tx_buf); } } + +#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/cpu/mc1322x/src/default_lowlevel.c b/cpu/mc1322x/src/default_lowlevel.c index 1f603f113..27b35a889 100644 --- a/cpu/mc1322x/src/default_lowlevel.c +++ b/cpu/mc1322x/src/default_lowlevel.c @@ -47,7 +47,7 @@ void default_vreg_init(void) { void uart1_init(uint16_t inc, uint16_t mod, uint8_t samp) { - /* UART must be disabled to set the baudrate */ + /* UART must be disabled to set the baudrate */ *UART1_UCON = 0; *UART1_UBRCNT = ( inc << 16 ) | mod; @@ -63,18 +63,27 @@ void uart1_init(uint16_t inc, uint16_t mod, uint8_t samp) { /* 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_UCON = (1 << 0) | (1 << 1); /* enable receive, transmit */ + +#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 + if(samp == UCON_SAMP_16X) set_bit(*UART1_UCON,UCON_SAMP); *GPIO_FUNC_SEL0 = ( (0x01 << (14*2)) | (0x01 << (15*2)) ); /* set GPIO15-14 to UART (UART1 TX and RX)*/ - + /* interrupt when there are this number or more bytes free in the TX buffer*/ *UART1_UTXCON = 16; + u1_tx_head = 0; u1_tx_tail = 0; - 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); } diff --git a/platform/redbee-econotag/contiki-mc1322x-main.c b/platform/redbee-econotag/contiki-mc1322x-main.c index 268d1602a..e49282d65 100644 --- a/platform/redbee-econotag/contiki-mc1322x-main.c +++ b/platform/redbee-econotag/contiki-mc1322x-main.c @@ -48,6 +48,7 @@ #include "lib/random.h" #include "net/netstack.h" #include "net/mac/frame802154.h" +#include "lib/include/uart1.h" #if WITH_UIP6 #include "net/sicslowpan.h" @@ -490,7 +491,6 @@ main(void) cop_service(); #endif - /* TODO: replace this with a uart rx interrupt */ if(uart1_input_handler != NULL) { if(uart1_can_get()) { uart1_input_handler(uart1_getc()); diff --git a/tools/tunslip6.c b/tools/tunslip6.c index 82ab3f433..2b1c28acf 100644 --- a/tools/tunslip6.c +++ b/tools/tunslip6.c @@ -60,7 +60,7 @@ const char *netmask; int slipfd = 0; uint16_t basedelay=0,delaymsec=0; uint32_t startsec,startmsec,delaystartsec,delaystartmsec; -int timestamp = 0; +int timestamp = 0, flowcontrol=0; int ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); @@ -172,7 +172,7 @@ serial_to_tun(FILE *inslip, int outfd) if(inbufptr >= sizeof(uip.inbuf)) { inbufptr = 0; if(timestamp) stamptime(); - fprintf(stderr, "*** dropping too large packet\n"); + fprintf(stderr, "*** dropping large %d byte packet\n",inbufptr); } ret = fread(&c, 1, 1, inslip); #ifdef linux @@ -459,7 +459,10 @@ stty_telos(int fd) /* Nonblocking read. */ tty.c_cc[VTIME] = 0; tty.c_cc[VMIN] = 0; - tty.c_cflag &= ~CRTSCTS; + if (flowcontrol) + tty.c_cflag |= CRTSCTS; + else + tty.c_cflag &= ~CRTSCTS; tty.c_cflag &= ~HUPCL; tty.c_cflag &= ~CLOCAL; @@ -616,12 +619,16 @@ main(int argc, char **argv) prog = argv[0]; setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ - while((c = getopt(argc, argv, "B:D:Lhs:t:v::d::a:p:T")) != -1) { + while((c = getopt(argc, argv, "B:H:D:Lhs:t:v::d::a:p:T")) != -1) { switch(c) { case 'B': baudrate = atoi(optarg); break; + case 'H': + flowcontrol=1; + break; + case 'L': timestamp=1; break; @@ -671,6 +678,7 @@ fprintf(stderr,"usage: %s [options] ipaddress\n", prog); fprintf(stderr,"example: tunslip6 -L -v2 -s ttyUSB1 aaaa::1/64\n"); fprintf(stderr,"Options are:\n"); fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200 (default)\n"); +fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n"); fprintf(stderr," -L Log output format (adds time stamps)\n"); fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n"); fprintf(stderr," -T Make tap interface (default is tun interface)\n"); @@ -696,7 +704,7 @@ exit(1); argv += (optind - 1); if(argc != 2 && argc != 3) { - err(1, "usage: %s [-B baudrate] [-L] [-s siodev] [-t tundev] [-T] [-v verbosity] [-d delay] [-a serveraddress] [-p serverport] ipaddress", prog); + err(1, "usage: %s [-B baudrate] [-H] [-L] [-s siodev] [-t tundev] [-T] [-v verbosity] [-d delay] [-a serveraddress] [-p serverport] ipaddress", prog); } ipaddr = argv[1];