nuclear@2: #ifndef F_CPU nuclear@0: #ifdef XTAL nuclear@0: #define F_CPU XTAL nuclear@0: #else nuclear@0: #warning "compiled for 1mhz internal rc osc. serial comms won't work" nuclear@0: #define F_CPU 1000000 nuclear@0: #endif nuclear@2: #endif nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: static int uart_send_char(char c, FILE *fp); nuclear@0: static int uart_get_char(FILE *fp); nuclear@0: nuclear@0: #define BUF_SZ 16 nuclear@0: #define BUF_IDX_MASK (BUF_SZ - 1) nuclear@0: #define NEXT_IDX(x) (((x) + 1) & BUF_IDX_MASK) nuclear@0: static char outbuf[BUF_SZ]; nuclear@0: static volatile unsigned char out_rd, out_wr; nuclear@0: static char inbuf[BUF_SZ]; nuclear@0: static volatile unsigned char in_rd, in_wr; nuclear@0: nuclear@0: static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW); nuclear@0: nuclear@0: nuclear@0: nuclear@0: void init_serial(long baud) nuclear@0: { nuclear@2: unsigned int ubrr_val = F_CPU / 16 / baud - 1; nuclear@0: nuclear@0: power_usart0_enable(); nuclear@0: nuclear@0: /* set baud generator timer reset value */ nuclear@0: UBRR0H = (unsigned char)(ubrr_val >> 8); nuclear@0: UBRR0L = (unsigned char)ubrr_val; nuclear@0: nuclear@0: /* enable rx/tx and recv interrupt */ nuclear@0: UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); nuclear@0: /* set frame format: 8n1 */ nuclear@0: UCSR0C = 3 << UCSZ00; nuclear@0: nuclear@0: stdin = stdout = stderr = &std_stream; nuclear@0: } nuclear@0: nuclear@0: int have_input(void) nuclear@0: { nuclear@0: return in_wr != in_rd; nuclear@0: } nuclear@0: nuclear@0: static int uart_send_char(char c, FILE *fp) nuclear@0: { nuclear@0: /*int next;*/ nuclear@0: nuclear@0: while((UCSR0A & (1 << UDRE0)) == 0); nuclear@0: UDR0 = (unsigned char)c; nuclear@0: #if 0 nuclear@0: next = NEXT_IDX(out_wr); nuclear@0: while(next == out_rd); nuclear@0: nuclear@0: outbuf[out_wr] = c; nuclear@0: out_wr = next; nuclear@0: nuclear@0: /* enable the Tx data register empty interrupt */ nuclear@0: UCSR0B |= 1 << UDRIE0; nuclear@0: #endif nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static int uart_get_char(FILE *fp) nuclear@0: { nuclear@0: char c; nuclear@0: nuclear@0: while(in_rd == in_wr); nuclear@0: nuclear@0: c = inbuf[in_rd]; nuclear@0: in_rd = NEXT_IDX(in_rd); nuclear@0: return c; nuclear@0: } nuclear@0: nuclear@0: ISR(USART_RX_vect) nuclear@0: { nuclear@0: char c = UDR0; nuclear@0: nuclear@0: inbuf[in_wr] = c; nuclear@0: in_wr = NEXT_IDX(in_wr); nuclear@0: } nuclear@0: nuclear@0: /* USART Tx data register empty (can send more data) */ nuclear@0: ISR(USART_UDRE_vect) nuclear@0: { nuclear@0: if(out_rd != out_wr) { nuclear@0: UDR0 = outbuf[out_rd]; nuclear@0: out_rd = NEXT_IDX(out_rd); nuclear@0: } else { nuclear@0: /* no more data to send for now, disable the interrupt */ nuclear@0: UCSR0B &= ~(1 << UDRIE0); nuclear@0: } nuclear@0: }