/* uart.c: UART access routines */ #include #include "bits.h" #include "config.h" #include "uart.h" #include "led.h" /* A few symbols to make this code work for all four UARTs */ #if defined(CONFIG_UART_NUM) && CONFIG_UART_NUM == 0 # define UART_PCONBIT 3 # define UART_PCLKREG PCLKSEL0 # define UART_PCLKBIT 6 # define UART_REGS LPC_UART0 # define UART_HANDLER UART0_IRQHandler # define UART_IRQ UART0_IRQn #elif CONFIG_UART_NUM == 1 # define UART_PCONBIT 4 # define UART_PCLKREG PCLKSEL0 # define UART_PCLKBIT 8 # define UART_REGS LPC_UART1 # define UART_HANDLER UART1_IRQHandler # define UART_IRQ UART1_IRQn #elif CONFIG_UART_NUM == 2 # define UART_PCONBIT 24 # define UART_PCLKREG PCLKSEL1 # define UART_PCLKBIT 16 # define UART_REGS LPC_UART2 # define UART_HANDLER UART2_IRQHandler # define UART_IRQ UART2_IRQn #elif CONFIG_UART_NUM == 3 # define UART_PCONBIT 25 # define UART_PCLKREG PCLKSEL1 # define UART_PCLKBIT 18 # define UART_REGS LPC_UART3 # define UART_HANDLER UART3_IRQHandler # define UART_IRQ UART3_IRQn #else # error CONFIG_UART_NUM is not set or has an invalid value! #endif static uint8_t uart_lookupratio( float f_fr ) { uint16_t errors[72] = {0, 67, 71, 77, 83, 91, 100, 111, 125, 133, 143, 154, 167, 182, 200, 214, 222, 231, 250, 267, 273, 286, 300, 308, 333, 357, 364, 375, 385, 400, 417, 429, 444, 455, 462, 467, 500, 533, 538, 545, 556, 571, 583, 600, 615, 625, 636, 643, 667, 692, 700, 714, 727, 733, 750, 769, 778, 786, 800, 818, 833, 846, 857, 867, 875, 889, 900, 909, 917, 923, 929, 933 }; uint8_t ratios[72] = {0x10, 0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0xf2, 0x71, 0xd2, 0x61, 0xb2, 0x51, 0xe3, 0x92, 0xd3, 0x41, 0xf4, 0xb3, 0x72, 0xa3, 0xd4, 0x31, 0xe5, 0xb4, 0x83, 0xd5, 0x52, 0xc5, 0x73, 0x94, 0xb5, 0xd6, 0xf7, 0x21, 0xf8, 0xd7, 0xb6, 0x95, 0x74, 0xc7, 0x53, 0xd8, 0x85, 0xb7, 0xe9, 0x32, 0xd9, 0xa7, 0x75, 0xb8, 0xfb, 0x43, 0xda, 0x97, 0xeb, 0x54, 0xb9, 0x65, 0xdb, 0x76, 0xfd, 0x87, 0x98, 0xa9, 0xba, 0xcb, 0xdc, 0xed, 0xfe }; int fr = ( f_fr - 1 ) * 1000; int i = 0, i_result = 0; int err = 0, lasterr = 1000; for ( i = 0; i < 72; i++ ) { if ( fr < errors[i] ) { err = errors[i] - fr; } else { err = fr - errors[i]; } if ( err < lasterr ) { i_result = i; lasterr = err; } } return ratios[i_result]; } static uint32_t baud2divisor( unsigned int baudrate ) { uint32_t int_ratio; uint32_t error; uint32_t dl = 0; float f_ratio; float f_fr; float f_dl; float f_pclk = ( float )CONFIG_CPU_FREQUENCY / CONFIG_UART_PCLKDIV; uint8_t fract_ratio; f_ratio = ( f_pclk / 16 / baudrate ); int_ratio = ( int )f_ratio; error = ( f_ratio * 1000 ) - ( int_ratio * 1000 ); if ( error > 990 ) { int_ratio++; } else if ( error > 10 ) { f_fr = 1.5; f_dl = f_pclk / ( 16 * baudrate * ( f_fr ) ); dl = ( int )f_dl; f_fr = f_pclk / ( 16 * baudrate * dl ); fract_ratio = uart_lookupratio( f_fr ); } if ( !dl ) { return int_ratio; } else { return ( ( fract_ratio << 16 ) & 0xff0000 ) | dl; } } static char txbuf[1 << CONFIG_UART_TX_BUF_SHIFT]; static volatile unsigned int read_idx, write_idx; void UART_HANDLER( void ) { int iir = UART_REGS->IIR; if ( !( iir & 1 ) ) { /* Interrupt is pending */ switch ( iir & 14 ) { #if CONFIG_UART_NUM == 1 case 0: /* modem status */ ( void ) UART_REGS->MSR; // dummy read to clear break; #endif case 2: /* THR empty - send */ if ( read_idx != write_idx ) { int maxchars = 16; while ( read_idx != write_idx && --maxchars > 0 ) { UART_REGS->THR = ( unsigned char )txbuf[read_idx]; read_idx = ( read_idx + 1 ) & ( sizeof( txbuf ) - 1 ); } if ( read_idx == write_idx ) { /* buffer empty - turn off THRE interrupt */ BITBAND( UART_REGS->IER, 1 ) = 0; } } break; case 12: /* RX timeout */ case 4: /* data received - not implemented yet */ ( void ) UART_REGS->RBR; // dummy read to clear break; case 6: /* RX error */ ( void ) UART_REGS->LSR; // dummy read to clear default: break; } } } void uart_putc( char c ) { if ( c == '\n' ) { uart_putc( '\r' ); } unsigned int tmp = ( write_idx + 1 ) & ( sizeof( txbuf ) - 1 ) ; if ( read_idx == write_idx && ( BITBAND( UART_REGS->LSR, 5 ) ) ) { /* buffer empty, THR empty -> send immediately */ UART_REGS->THR = ( unsigned char )c; } else { #ifdef CONFIG_UART_DEADLOCKABLE while ( tmp == read_idx ) ; #endif BITBAND( UART_REGS->IER, 1 ) = 0; // turn off UART interrupt txbuf[write_idx] = c; write_idx = tmp; BITBAND( UART_REGS->IER, 1 ) = 1; } } /* Polling version only */ unsigned char uart_getc( void ) { /* wait for character */ while ( !( BITBAND( UART_REGS->LSR, 0 ) ) ) ; return UART_REGS->RBR; } /* Returns true if a char is ready */ unsigned char uart_gotc( void ) { return BITBAND( UART_REGS->LSR, 0 ); } void uart_init( void ) { uint32_t div; /* Turn on power to UART */ BITBAND( LPC_SC->PCONP, UART_PCONBIT ) = 1; /* UART clock = CPU clock - this block is reduced at compile-time */ if ( CONFIG_UART_PCLKDIV == 1 ) { BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT ) = 1; BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT + 1 ) = 0; } else if ( CONFIG_UART_PCLKDIV == 2 ) { BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT ) = 0; BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT + 1 ) = 1; } else if ( CONFIG_UART_PCLKDIV == 4 ) { BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT ) = 0; BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT + 1 ) = 0; } else // Fallback: Divide by 8 { BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT ) = 1; BITBAND( LPC_SC->UART_PCLKREG, UART_PCLKBIT + 1 ) = 1; } /* set baud rate - no fractional stuff for now */ UART_REGS->LCR = BV( 7 ) | 3; // always 8n1 div = baud2divisor( CONFIG_UART_BAUDRATE ); UART_REGS->DLL = div & 0xff; UART_REGS->DLM = ( div >> 8 ) & 0xff; BITBAND( UART_REGS->LCR, 7 ) = 0; if ( div & 0xff0000 ) { UART_REGS->FDR = ( div >> 16 ) & 0xff; } /* reset and enable FIFO */ UART_REGS->FCR = BV( 0 ); /* enable transmit interrupt */ BITBAND( UART_REGS->IER, 1 ) = 1; NVIC_EnableIRQ( UART_IRQ ); UART_REGS->THR = '?'; } /* --- generic code below --- */ void uart_puthex( uint8_t num ) { uint8_t tmp; tmp = ( num & 0xf0 ) >> 4; if ( tmp < 10 ) { uart_putc( '0' + tmp ); } else { uart_putc( 'a' + tmp - 10 ); } tmp = num & 0x0f; if ( tmp < 10 ) { uart_putc( '0' + tmp ); } else { uart_putc( 'a' + tmp - 10 ); } } void uart_trace( void *ptr, uint16_t start, uint16_t len, uint32_t addr ) { uint16_t i; uint8_t j; uint8_t ch; uint8_t *data = ptr; data += start; for ( i = 0; i < len; i += 16 ) { uart_puthex( ( addr + start ) >> 16 ); uart_puthex( ( ( addr + start ) >> 8 ) & 0xff ); uart_puthex( ( addr + start ) & 0xff ); uart_putc( '|' ); uart_putc( ' ' ); for ( j = 0; j < 16; j++ ) { if ( i + j < len ) { ch = *( data + j ); uart_puthex( ch ); } else { uart_putc( ' ' ); uart_putc( ' ' ); } uart_putc( ' ' ); } uart_putc( '|' ); for ( j = 0; j < 16; j++ ) { if ( i + j < len ) { ch = *( data++ ); if ( ch < 32 || ch > 0x7e ) { ch = '.'; } uart_putc( ch ); } else { uart_putc( ' ' ); } } uart_putc( '|' ); uart_putcrlf(); start += 16; } } void uart_flush( void ) { while ( read_idx != write_idx ) ; } void uart_puts( const char *text ) { while ( *text ) { uart_putc( *text++ ); } }