blob: f9106514ad28f830c183a91205700a658513ecf3 [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
8// Currently hard-coded for 8-bit + odd parity + start bit + stop bit.
9void 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;
24 module_->C1 = M_UART_M /* 9 data bits */ |
25 M_UART_ILT /* only detect idle after stop bit */ |
26 M_UART_PE /* enable parity */ | M_UART_PT /* odd parity */;
27 module_->C4 = V_UART_BRFA(brfa);
28 }
29 {
30 const uint8_t pfifo = module_->PFIFO;
31 tx_fifo_size_ = G_UART_TXFIFOSIZE(pfifo);
32 rx_fifo_size_ = G_UART_RXFIFOSIZE(pfifo);
33 }
34
35 // When C1[M] is set and C4[M10] is cleared, the UART is configured for 9-bit
36 // data characters. If C1[PE] is enabled, the ninth bit is either C3[T8/R8] or
37 // the internally generated parity bit
38
39 // TODO(Brian): M_UART_TIE /* Enable TX interrupt or DMA */ |
40 // M_UART_RIE /* Enable RX interrupt or DMA */
41 // Also set in C5: M_UART_TDMAS /* Do DMA for TX */ |
42 // M_UART_RDMAS /* Do DMA for RX */
43 c2_value_ = M_UART_TE;
44 module_->C2 = c2_value_;
45 module_->PFIFO =
46 M_UART_TXFE /* Enable TX FIFO */ | M_UART_RXFE /* Enable RX FIFO */;
47 module_->CFIFO =
48 M_UART_TXFLUSH /* Flush TX FIFO */ | M_UART_RXFLUSH /* Flush RX FIFO */;
49 // TODO(Brian): Adjust for DMA?
50 module_->TWFIFO = tx_fifo_size_ - 1;
51 module_->RWFIFO = rx_fifo_size_ - 1;
52}
53
54void Uart::DoWrite(gsl::span<char> data) {
55 for (int i = 0; i < data.size(); ++i) {
56 while (!SpaceAvailable()) {
57 }
58 WriteCharacter(data[i]);
59 }
60}
61
62Uart::~Uart() { DisableTransmitInterrupt(); }
63
64void InterruptBufferedUart::Initialize(int baud_rate) {
65 uart_.Initialize(baud_rate);
66}
67
68void InterruptBufferedUart::Write(gsl::span<char> data,
69 const DisableInterrupts &disable_interrupts) {
70 uart_.EnableTransmitInterrupt();
71 static_assert(buffer_.size() >= 8,
72 "Need enough space to not turn the interrupt off each time");
73 while (!data.empty()) {
74 const int bytes_written = buffer_.PushSpan(data);
75 data = data.subspan(bytes_written);
76 WriteCharacters(data.empty(), disable_interrupts);
77 }
78}
79
80void InterruptBufferedUart::WriteCharacters(bool disable_empty,
81 const DisableInterrupts &) {
82 while (true) {
83 if (buffer_.empty()) {
84 if (disable_empty) {
85 uart_.DisableTransmitInterrupt();
86 }
87 return;
88 }
89 if (!uart_.SpaceAvailable()) {
90 return;
91 }
92 uart_.WriteCharacter(buffer_.PopSingle());
93 }
94}
95
96} // namespace teensy
97} // namespace frc971