blob: 9cd4014a442b4898faf24f174359711ae10bc9d6 [file] [log] [blame]
Brian Silverman55c62022018-09-03 19:13:44 -07001#include "motors/peripheral/uart.h"
2
3#include <stdint.h>
4
5namespace frc971 {
6namespace teensy {
7
James Kuszmaul0844eb22018-09-08 15:54:04 -07008// Currently hard-coded for 8-bit + no parity + start bit + stop bit.
Brian Silverman55c62022018-09-03 19:13:44 -07009void Uart::Initialize(int baud_rate) {
10 {
11 // UART baud rate = UART module clock / (16 * (SBR[12:0] + BRFD))
12 // BRFD = BRFA (bitfield) / 32
13 const int desired_receiver_clock = baud_rate * 16;
14 const int sbr_and_brfd32 =
15 ((static_cast<int64_t>(module_clock_frequency_) * UINT64_C(64) /
16 static_cast<int64_t>(desired_receiver_clock)) +
17 1) /
18 2;
19 const int sbr = sbr_and_brfd32 / 32;
20 const int brfa = sbr_and_brfd32 % 32;
21
22 module_->BDH = (sbr >> 8) & 0x1F;
23 module_->BDL = sbr & 0xFF;
James Kuszmaul0844eb22018-09-08 15:54:04 -070024 module_->C1 = M_UART_ILT /* only detect idle after stop bit */ |
25 M_UART_PT /* odd parity */;
Brian Silverman55c62022018-09-03 19:13:44 -070026 module_->C4 = V_UART_BRFA(brfa);
27 }
28 {
29 const uint8_t pfifo = module_->PFIFO;
30 tx_fifo_size_ = G_UART_TXFIFOSIZE(pfifo);
31 rx_fifo_size_ = G_UART_RXFIFOSIZE(pfifo);
32 }
33
34 // When C1[M] is set and C4[M10] is cleared, the UART is configured for 9-bit
35 // data characters. If C1[PE] is enabled, the ninth bit is either C3[T8/R8] or
36 // the internally generated parity bit
37
38 // TODO(Brian): M_UART_TIE /* Enable TX interrupt or DMA */ |
39 // M_UART_RIE /* Enable RX interrupt or DMA */
40 // Also set in C5: M_UART_TDMAS /* Do DMA for TX */ |
41 // M_UART_RDMAS /* Do DMA for RX */
Brian Silverman4f958792019-02-16 18:20:04 -080042 c2_value_ = 0;
Brian Silverman55c62022018-09-03 19:13:44 -070043 module_->C2 = c2_value_;
44 module_->PFIFO =
45 M_UART_TXFE /* Enable TX FIFO */ | M_UART_RXFE /* Enable RX FIFO */;
46 module_->CFIFO =
47 M_UART_TXFLUSH /* Flush TX FIFO */ | M_UART_RXFLUSH /* Flush RX FIFO */;
Brian Silverman4f958792019-02-16 18:20:04 -080048 c2_value_ = M_UART_TE | M_UART_RE;
49 module_->C2 = c2_value_;
Brian Silverman55c62022018-09-03 19:13:44 -070050 // TODO(Brian): Adjust for DMA?
51 module_->TWFIFO = tx_fifo_size_ - 1;
Brian Silverman4f958792019-02-16 18:20:04 -080052 module_->RWFIFO = 1;
Brian Silverman55c62022018-09-03 19:13:44 -070053}
54
Brian Silverman4787a6e2018-10-06 16:00:54 -070055void Uart::DoWrite(gsl::span<const char> data) {
Brian Silverman4f958792019-02-16 18:20:04 -080056 // In theory, we could be more efficient about this by writing the number of
57 // bytes we know there's space for and only calling SpaceAvailable() (or
58 // otherwise reading S1) before the final one. In practice, the FIFOs are so
59 // short on this part it probably won't help anything.
Brian Silverman55c62022018-09-03 19:13:44 -070060 for (int i = 0; i < data.size(); ++i) {
61 while (!SpaceAvailable()) {
62 }
63 WriteCharacter(data[i]);
64 }
65}
66
Brian Silverman4f958792019-02-16 18:20:04 -080067aos::SizedArray<char, 4> Uart::DoRead() {
68 // In theory, we could be more efficient about this by reading the number of
69 // bytes we know to be accessible and only calling DataAvailable() (or
70 // otherwise reading S1) before the final one. In practice, the FIFOs are so
71 // short on this part it probably won't help anything.
72 aos::SizedArray<char, 4> result;
73 while (DataAvailable() && !result.full()) {
74 result.push_back(ReadCharacter());
75 }
76 return result;
77}
78
79Uart::~Uart() {
80 DoDisableTransmitInterrupt();
81 DoDisableReceiveInterrupt();
82}
83
84InterruptBufferedUart::~InterruptBufferedUart() {
85 uart_.DisableReceiveInterrupt(DisableInterrupts());
86}
Brian Silverman55c62022018-09-03 19:13:44 -070087
88void InterruptBufferedUart::Initialize(int baud_rate) {
89 uart_.Initialize(baud_rate);
Brian Silverman4f958792019-02-16 18:20:04 -080090 {
91 DisableInterrupts disable_interrupts;
92 uart_.EnableReceiveInterrupt(disable_interrupts);
93 }
Brian Silverman55c62022018-09-03 19:13:44 -070094}
95
Brian Silverman4787a6e2018-10-06 16:00:54 -070096void InterruptBufferedUart::Write(gsl::span<const char> data) {
Brian Silverman12fec3f2018-09-09 16:09:50 -070097 DisableInterrupts disable_interrupts;
Brian Silverman4f958792019-02-16 18:20:04 -080098 uart_.EnableTransmitInterrupt(disable_interrupts);
Brian Silverman55c62022018-09-03 19:13:44 -070099 while (!data.empty()) {
Brian Silverman4f958792019-02-16 18:20:04 -0800100 const int bytes_written = transmit_buffer_.PushSpan(data);
Brian Silverman55c62022018-09-03 19:13:44 -0700101 data = data.subspan(bytes_written);
102 WriteCharacters(data.empty(), disable_interrupts);
Brian Silverman12fec3f2018-09-09 16:09:50 -0700103 ReenableInterrupts{&disable_interrupts};
Brian Silverman55c62022018-09-03 19:13:44 -0700104 }
105}
106
Brian Silverman4f958792019-02-16 18:20:04 -0800107gsl::span<char> InterruptBufferedUart::Read(gsl::span<char> buffer) {
108 size_t bytes_read = 0;
109 {
110 DisableInterrupts disable_interrupts;
111 const gsl::span<const char> read_data =
112 receive_buffer_.PopSpan(buffer.size());
113 std::copy(read_data.begin(), read_data.end(), buffer.begin());
114 bytes_read += read_data.size();
115 }
116 {
117 DisableInterrupts disable_interrupts;
118 const gsl::span<const char> read_data =
119 receive_buffer_.PopSpan(buffer.size() - bytes_read);
120 std::copy(read_data.begin(), read_data.end(),
121 buffer.subspan(bytes_read).begin());
122 bytes_read += read_data.size();
123 }
124 return buffer.subspan(0, bytes_read);
125}
126
127void InterruptBufferedUart::WriteCharacters(
128 bool disable_empty, const DisableInterrupts &disable_interrupts) {
Brian Silverman55c62022018-09-03 19:13:44 -0700129 while (true) {
Brian Silverman4f958792019-02-16 18:20:04 -0800130 if (transmit_buffer_.empty()) {
Brian Silverman55c62022018-09-03 19:13:44 -0700131 if (disable_empty) {
Brian Silverman4f958792019-02-16 18:20:04 -0800132 uart_.DisableTransmitInterrupt(disable_interrupts);
Brian Silverman55c62022018-09-03 19:13:44 -0700133 }
134 return;
135 }
136 if (!uart_.SpaceAvailable()) {
137 return;
138 }
Brian Silverman4f958792019-02-16 18:20:04 -0800139 uart_.WriteCharacter(transmit_buffer_.PopSingle());
140 }
141}
142
143void InterruptBufferedUart::ReadCharacters(const DisableInterrupts &) {
144 while (true) {
145 if (receive_buffer_.full()) {
146 return;
147 }
148 if (!uart_.DataAvailable()) {
149 return;
150 }
151 receive_buffer_.PushSingle(uart_.ReadCharacter());
Brian Silverman55c62022018-09-03 19:13:44 -0700152 }
153}
154
155} // namespace teensy
156} // namespace frc971