blob: 408bbfd5581cc63222ee8f7934a4e6f2186aa9f5 [file] [log] [blame]
Brian Silverman55c62022018-09-03 19:13:44 -07001#include "motors/peripheral/uart.h"
2
3#include <stdint.h>
4
Stephan Pleinesf63bde82024-01-13 15:59:33 -08005namespace frc971::teensy {
Brian Silverman55c62022018-09-03 19:13:44 -07006
James Kuszmaul0844eb22018-09-08 15:54:04 -07007// Currently hard-coded for 8-bit + no parity + start bit + stop bit.
Brian Silverman55c62022018-09-03 19:13:44 -07008void Uart::Initialize(int baud_rate) {
9 {
10 // UART baud rate = UART module clock / (16 * (SBR[12:0] + BRFD))
11 // BRFD = BRFA (bitfield) / 32
12 const int desired_receiver_clock = baud_rate * 16;
13 const int sbr_and_brfd32 =
14 ((static_cast<int64_t>(module_clock_frequency_) * UINT64_C(64) /
15 static_cast<int64_t>(desired_receiver_clock)) +
16 1) /
17 2;
18 const int sbr = sbr_and_brfd32 / 32;
19 const int brfa = sbr_and_brfd32 % 32;
20
21 module_->BDH = (sbr >> 8) & 0x1F;
22 module_->BDL = sbr & 0xFF;
James Kuszmaul0844eb22018-09-08 15:54:04 -070023 module_->C1 = M_UART_ILT /* only detect idle after stop bit */ |
24 M_UART_PT /* odd parity */;
Brian Silverman55c62022018-09-03 19:13:44 -070025 module_->C4 = V_UART_BRFA(brfa);
26 }
27 {
28 const uint8_t pfifo = module_->PFIFO;
29 tx_fifo_size_ = G_UART_TXFIFOSIZE(pfifo);
30 rx_fifo_size_ = G_UART_RXFIFOSIZE(pfifo);
31 }
32
33 // When C1[M] is set and C4[M10] is cleared, the UART is configured for 9-bit
34 // data characters. If C1[PE] is enabled, the ninth bit is either C3[T8/R8] or
35 // the internally generated parity bit
36
37 // TODO(Brian): M_UART_TIE /* Enable TX interrupt or DMA */ |
38 // M_UART_RIE /* Enable RX interrupt or DMA */
39 // Also set in C5: M_UART_TDMAS /* Do DMA for TX */ |
40 // M_UART_RDMAS /* Do DMA for RX */
Brian Silverman4f958792019-02-16 18:20:04 -080041 c2_value_ = 0;
Brian Silverman55c62022018-09-03 19:13:44 -070042 module_->C2 = c2_value_;
43 module_->PFIFO =
44 M_UART_TXFE /* Enable TX FIFO */ | M_UART_RXFE /* Enable RX FIFO */;
45 module_->CFIFO =
46 M_UART_TXFLUSH /* Flush TX FIFO */ | M_UART_RXFLUSH /* Flush RX FIFO */;
Brian Silverman4f958792019-02-16 18:20:04 -080047 c2_value_ = M_UART_TE | M_UART_RE;
48 module_->C2 = c2_value_;
Brian Silverman55c62022018-09-03 19:13:44 -070049 // TODO(Brian): Adjust for DMA?
50 module_->TWFIFO = tx_fifo_size_ - 1;
Brian Silverman4f958792019-02-16 18:20:04 -080051 module_->RWFIFO = 1;
Brian Silverman55c62022018-09-03 19:13:44 -070052}
53
Austin Schuh7fe04492022-01-02 13:37:21 -080054void Uart::DoWrite(absl::Span<const char> data) {
Brian Silverman4f958792019-02-16 18:20:04 -080055 // In theory, we could be more efficient about this by writing the number of
56 // bytes we know there's space for and only calling SpaceAvailable() (or
57 // otherwise reading S1) before the final one. In practice, the FIFOs are so
58 // short on this part it probably won't help anything.
Austin Schuh7fe04492022-01-02 13:37:21 -080059 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman55c62022018-09-03 19:13:44 -070060 while (!SpaceAvailable()) {
61 }
62 WriteCharacter(data[i]);
63 }
64}
65
Brian Silverman4f958792019-02-16 18:20:04 -080066aos::SizedArray<char, 4> Uart::DoRead() {
67 // In theory, we could be more efficient about this by reading the number of
68 // bytes we know to be accessible and only calling DataAvailable() (or
69 // otherwise reading S1) before the final one. In practice, the FIFOs are so
70 // short on this part it probably won't help anything.
71 aos::SizedArray<char, 4> result;
Tyler Chatowd0a49742022-02-25 22:06:19 -080072 while (DataAvailable() && result.size() != result.capacity()) {
Brian Silverman4f958792019-02-16 18:20:04 -080073 result.push_back(ReadCharacter());
74 }
75 return result;
76}
77
78Uart::~Uart() {
79 DoDisableTransmitInterrupt();
80 DoDisableReceiveInterrupt();
81}
82
83InterruptBufferedUart::~InterruptBufferedUart() {
84 uart_.DisableReceiveInterrupt(DisableInterrupts());
85}
Brian Silverman55c62022018-09-03 19:13:44 -070086
87void InterruptBufferedUart::Initialize(int baud_rate) {
88 uart_.Initialize(baud_rate);
Brian Silverman4f958792019-02-16 18:20:04 -080089 {
90 DisableInterrupts disable_interrupts;
91 uart_.EnableReceiveInterrupt(disable_interrupts);
92 }
Brian Silverman55c62022018-09-03 19:13:44 -070093}
94
Austin Schuh7fe04492022-01-02 13:37:21 -080095void InterruptBufferedUart::Write(absl::Span<const char> data) {
Brian Silverman12fec3f2018-09-09 16:09:50 -070096 DisableInterrupts disable_interrupts;
Brian Silverman4f958792019-02-16 18:20:04 -080097 uart_.EnableTransmitInterrupt(disable_interrupts);
Brian Silverman55c62022018-09-03 19:13:44 -070098 while (!data.empty()) {
Brian Silverman4f958792019-02-16 18:20:04 -080099 const int bytes_written = transmit_buffer_.PushSpan(data);
Brian Silverman55c62022018-09-03 19:13:44 -0700100 data = data.subspan(bytes_written);
101 WriteCharacters(data.empty(), disable_interrupts);
Brian Silverman12fec3f2018-09-09 16:09:50 -0700102 ReenableInterrupts{&disable_interrupts};
Brian Silverman55c62022018-09-03 19:13:44 -0700103 }
104}
105
Austin Schuh7fe04492022-01-02 13:37:21 -0800106absl::Span<char> InterruptBufferedUart::Read(absl::Span<char> buffer) {
Brian Silverman4f958792019-02-16 18:20:04 -0800107 size_t bytes_read = 0;
108 {
109 DisableInterrupts disable_interrupts;
Austin Schuh7fe04492022-01-02 13:37:21 -0800110 const absl::Span<const char> read_data =
Brian Silverman4f958792019-02-16 18:20:04 -0800111 receive_buffer_.PopSpan(buffer.size());
112 std::copy(read_data.begin(), read_data.end(), buffer.begin());
113 bytes_read += read_data.size();
114 }
115 {
116 DisableInterrupts disable_interrupts;
Austin Schuh7fe04492022-01-02 13:37:21 -0800117 const absl::Span<const char> read_data =
Brian Silverman4f958792019-02-16 18:20:04 -0800118 receive_buffer_.PopSpan(buffer.size() - bytes_read);
119 std::copy(read_data.begin(), read_data.end(),
120 buffer.subspan(bytes_read).begin());
121 bytes_read += read_data.size();
122 }
123 return buffer.subspan(0, bytes_read);
124}
125
126void InterruptBufferedUart::WriteCharacters(
127 bool disable_empty, const DisableInterrupts &disable_interrupts) {
Brian Silverman55c62022018-09-03 19:13:44 -0700128 while (true) {
Brian Silverman4f958792019-02-16 18:20:04 -0800129 if (transmit_buffer_.empty()) {
Brian Silverman55c62022018-09-03 19:13:44 -0700130 if (disable_empty) {
Brian Silverman4f958792019-02-16 18:20:04 -0800131 uart_.DisableTransmitInterrupt(disable_interrupts);
Brian Silverman55c62022018-09-03 19:13:44 -0700132 }
133 return;
134 }
135 if (!uart_.SpaceAvailable()) {
136 return;
137 }
Brian Silverman4f958792019-02-16 18:20:04 -0800138 uart_.WriteCharacter(transmit_buffer_.PopSingle());
139 }
140}
141
142void InterruptBufferedUart::ReadCharacters(const DisableInterrupts &) {
143 while (true) {
144 if (receive_buffer_.full()) {
145 return;
146 }
147 if (!uart_.DataAvailable()) {
148 return;
149 }
150 receive_buffer_.PushSingle(uart_.ReadCharacter());
Brian Silverman55c62022018-09-03 19:13:44 -0700151 }
152}
153
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800154} // namespace frc971::teensy