diff options
author | Jakob Odersky <jodersky@gmail.com> | 2014-01-25 14:47:07 +0100 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2014-01-25 14:47:07 +0100 |
commit | 7dd00b2267d991a102f18eacf3e2afacb570a299 (patch) | |
tree | 9138bc7ce4feba262a20063f94aceaba3ec30788 /kernel/serial/serial.c | |
parent | 9453a44cfc475b57319d1051c74f72753ca4f64c (diff) | |
download | mux-7dd00b2267d991a102f18eacf3e2afacb570a299.tar.gz mux-7dd00b2267d991a102f18eacf3e2afacb570a299.tar.bz2 mux-7dd00b2267d991a102f18eacf3e2afacb570a299.zip |
implement serial
Diffstat (limited to 'kernel/serial/serial.c')
-rw-r--r-- | kernel/serial/serial.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/kernel/serial/serial.c b/kernel/serial/serial.c new file mode 100644 index 0000000..6e88cd6 --- /dev/null +++ b/kernel/serial/serial.c @@ -0,0 +1,94 @@ +#include <avr/interrupt.h> +#include "serial/serial.h" +#include "sched/sched.h" +#include "bug/debug.h" + +static struct serial_device_t serial = SERIAL_DEVICE_INIT(serial); + +void serial_init(unsigned long baud) { + UCSR0A |= (1 << U2X0); //enable double speed transmission + uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2; + UBRR0H = baud_setting >> 8; + UBRR0L = baud_setting; + UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // 8-bit, no parity, 1 stop bit + UCSR0B &= ~(1 << UDRIE0); +} + +static inline int rbuffer_empty_safe(struct rbuffer_t* const rb) { + cli(); + int r = rbuffer_empty(rb); + sei(); + return r; +} + +size_t serial_read(char* const data, size_t size) { + while (rbuffer_empty_safe(&serial.rx_buffer)) { + cli(); + sleep_on(&serial.rx_q); + yield(); + } + cli(); + size_t r = rbuffer_read(&serial.rx_buffer, data, size); + sei(); + return r; +} + + +//called when byte is received +ISR(USART0_RX_vect, ISR_NAKED) { + SAVE_CONTEXT(); + char c = UDR0; + rbuffer_write_char(&serial.rx_buffer, c); + wake_all(&serial.rx_q); + RESTORE_CONTEXT(); + asm volatile ("reti"); +} + + +size_t serial_write(const char* const data, size_t size) { + cli(); + size_t r = rbuffer_write(&serial.tx_buffer, data, size); + sei(); + UCSR0B |= (1 << UDRIE0); + return r; +} + +//called when data register is empty +ISR(USART0_UDRE_vect) { + char c; + if (rbuffer_read_char(&serial.tx_buffer, &c)) { + UDR0 = c; + } else { + UCSR0B &= ~(1 << UDRIE0); //buffer empty, disable interruot + } +} +/* +void serial_read() { + ENTER_CRITICAL(); + list_move_tail(¤t->list, &serial_rx_q); + EXIT_CRITICAL(); + yield(); +} +*/ +/* +void serial_write_str(const char* const str) { + for (size_t i = 0; str[i] != '\0'; ++i) { + ENTER_CRITICAL(); + rbuffer_write(&serial_dev.tx_buffer, str[i]); + EXIT_CRITICAL(); + UCSR0B |= (1 << UDRIE0); + } +}*/ + + +/* +ISR(INT3_vect, ISR_NAKED) { + SAVE_CONTEXT(); + if (!list_empty(&serial_rx_q)) { + list_move_tail(serial_rx_q.next, &ready); + } + schedule(); + RESTORE_CONTEXT(); + asm volatile ("reti"); +} +*/ |