1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#include "serial.h"
/* Line Control
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* |dla| | parity | s | data |
*/
enum LineControlRegister : uint8_t {
d5bit = 0b00000000, // data bits
d6bit = 0b00000001,
d7bit = 0b00000010,
d8bit = 0b00000011,
none = 0b00000000, // parity bits
odd = 0b00001000,
even = 0b00011000,
mark = 0b00101000,
space = 0b00111000,
s1bit = 0b00000000, // stop bits
s2bit = 0b00000100, // 1.5 for 5bit data; 2 otherwise
dlab = 0b10000000, // divisor latch access bit
};
/* Line Status Register */
enum LineStatusRegister : uint8_t {
DR = 0b00000001, // data ready: see if there is data to read
OE = 0b00000010, // overrun error: see if there has been data lost
PE = 0b00000100, // parity error: see if there was error in transmission
FE = 0b00001000, // framing error: see if a stop bit was missing
BI = 0b00010000, // break indicator: see if there is a break in data input
THRE = 0b00100000, // transmitter holding register empty: see if transmission buffer is empty
TEMT = 0b01000000, // transmitter empty: see if transmitter is not doing anything
ERRO = 0b10000000, // impending error: see if there is an error with a word in the input buffer
};
// TODO InterruptControlRegister
// TODO FifoControlRegister
// TODO ModemControlRegister
SerialPort::SerialPort() {
/*
* The serial controller (UART) has a baud rate of 115200 ticks per second; to limit the speed of the port set the
* divisor:
* 1. set DLAB on LineControl
* 2. set BaudDiv_l
* 3. set BaudDiv_h
* 4. clear LineControl
*/
port.write(0x00, InterruptControl); // disable all interrupts
port.write(dlab, LineControl);
port.write(0x03, BaudDiv_l); // div_l: 0x03 38400 baud
port.write(0x00, BaudDiv_h); // div_h: 0x00
port.write(d8bit | none | s1bit, LineControl); // 8 bits, no parity, one stop bit
port.write(0xc7, FifoControl); // enable FIFO, clear, with 14-byte threshold
port.write(0x0b, ModemControl); // IRQ enabled, RTS/DSR set
// test serial port
port.write(0x1e, ModemControl); // set in loopback mode
port.write(0xae); // write 0xae to port
self_check_okay = (port.read() == 0xae);
// if not faulty, set in normal operation mode
if (self_check_okay) {
port.write(0x0f, ModemControl);
}
}
bool SerialPort::ready_read() {
return (port.read(LineStatus) & DR);
}
uint8_t SerialPort::read() {
while (!ready_read()) asm volatile("nop");
return port.read();
}
bool SerialPort::ready_write() {
return (port.read(LineStatus) & THRE);
}
void SerialPort::write(char c) {
while (!ready_write()) asm volatile("nop");
switch (c) {
case '\n':
port.write('\n');
port.write('\r');
break;
default:
port.write(static_cast<uint8_t>(c));
}
}
|