# HG changeset patch # User Tero Marttila # Date 1396545912 -10800 # Node ID dfe67409fbcd6364c0d0842db28ded0517bcb3de # Parent 237d1f5c1c324d1b00988a5b8e2a438f37749dd2 hello: interruptable timer sleep, with buffered serial IO diff -r 237d1f5c1c32 -r dfe67409fbcd src/hello.c --- a/src/hello.c Thu Apr 03 19:44:53 2014 +0300 +++ b/src/hello.c Thu Apr 03 20:25:12 2014 +0300 @@ -11,24 +11,29 @@ // LED sbi(&DDRB, DDB5); - serial_enable(); sei(); // blink char c = 'X'; - short timeout = 1000; + short timeout = 8000; short delta = 10; while (true) { - serial_write(c); - - // bitflip + // toggle xbi(&PORTB, PORTB5); - //timer_sleep(timeout); - //timeout += delta; + // sleep + if (timer_sleep(timeout)) { + c = '.'; + + } else if ((c = serial_read())) { + // got serial data + } else { + c = '?'; + } - c = serial_read(); + // output... + serial_write(c); } } diff -r 237d1f5c1c32 -r dfe67409fbcd src/serial.c --- a/src/serial.c Thu Apr 03 19:44:53 2014 +0300 +++ b/src/serial.c Thu Apr 03 20:25:12 2014 +0300 @@ -1,27 +1,30 @@ - +/** Serial modes */ static enum { SERIAL_MODE_ASYNC = 0b00, } serial_mode = SERIAL_MODE_ASYNC; static enum { SERIAL_BAUD_9600 = 103, - } serial_baud = SERIAL_BAUD_9600; static enum { SERIAL_PARITY_N = 0b00, - } serial_parity = SERIAL_PARITY_N; static enum { SERIAL_STOPBITS_1 = 0b0, - } serial_stopbits = SERIAL_STOPBITS_1; static enum { SERIAL_CHARS_8 = 0b011, } serial_chars = SERIAL_CHARS_8; +/** Serial state */ +char serial_rx = 0; +char serial_tx = 0; + +void serial_enable (char rx, char tx); + /* * Setup the UART for serial mode. */ @@ -55,13 +58,22 @@ | (0b0 << UCPOL0) ); UBRR0 = serial_baud; + + // active RX, idle TX + serial_enable(1, 0); } -void serial_enable () +void serial_enable (char rx, char tx) { UCSR0B = ( + // RX Complete Interrupt Enable + (!!rx << RXCIE0) + + // USART Data Register Empty Interrupt Enable + | (!!tx << UDRIE0) + // Receiver Enable - (0b1 << RXEN0) // enabled + | (0b1 << RXEN0) // enabled // Transmitter Enable | (0b1 << TXEN0) // enabled @@ -71,18 +83,47 @@ ); } +/* + * Read incoming into buffer. + */ +ISR(USART_RX_vect) +{ + serial_rx = UDR0; +} + +/* + * Write outgoing buffer. + */ +ISR(USART_UDRE_vect) +{ + UDR0 = serial_tx; + + // tx buffer consumed + serial_tx = 0; + + // idle tx + serial_enable(1, 0); +} + char serial_read () { - while (!tbi(&UCSR0A, RXC0)) - ; + char rx = serial_rx; - return UDR0; + // rx buffer consumed + serial_rx = 0; + + return rx; } void serial_write (char c) { - while (!tbi(&UCSR0A, UDRE0)) - ; - - UDR0 = c; + // XXX: atomic? + if (tbi(&UCSR0A, UDRE0)) { + // direct + UDR0 = c; + } else { + // buffered + serial_tx = c; + serial_enable(1, 1); + } } diff -r 237d1f5c1c32 -r dfe67409fbcd src/timer.c --- a/src/timer.c Thu Apr 03 19:44:53 2014 +0300 +++ b/src/timer.c Thu Apr 03 20:25:12 2014 +0300 @@ -64,8 +64,10 @@ /* * Sleep on timer1 interrupt. + * + * Returns 0 on interrupt, 1 on timeout. */ -void timer_sleep (int cycles) +char timer_sleep (int cycles) { // set timer timer1_start(cycles); @@ -81,12 +83,20 @@ ); // sleep - while (tbi(&TIMER_FLAGS, TIMER1_BUSY)) { - __asm__ ( "sleep" :: ); - } + __asm__ ( "sleep" :: ); // cleanup SMCR = 0; + + if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) { + timer1_stop(); + + // interrupt + return 0; + } else { + // timeout + return 1; + } }