blob: a901483563c5768974873b79b9d0849d5762a7ab [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 */
42 c2_value_ = M_UART_TE;
43 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 */;
48 // TODO(Brian): Adjust for DMA?
49 module_->TWFIFO = tx_fifo_size_ - 1;
50 module_->RWFIFO = rx_fifo_size_ - 1;
51}
52
53void Uart::DoWrite(gsl::span<char> data) {
54 for (int i = 0; i < data.size(); ++i) {
55 while (!SpaceAvailable()) {
56 }
57 WriteCharacter(data[i]);
58 }
59}
60
61Uart::~Uart() { DisableTransmitInterrupt(); }
62
63void InterruptBufferedUart::Initialize(int baud_rate) {
64 uart_.Initialize(baud_rate);
65}
66
67void InterruptBufferedUart::Write(gsl::span<char> data,
68 const DisableInterrupts &disable_interrupts) {
69 uart_.EnableTransmitInterrupt();
70 static_assert(buffer_.size() >= 8,
71 "Need enough space to not turn the interrupt off each time");
72 while (!data.empty()) {
73 const int bytes_written = buffer_.PushSpan(data);
74 data = data.subspan(bytes_written);
75 WriteCharacters(data.empty(), disable_interrupts);
76 }
77}
78
79void InterruptBufferedUart::WriteCharacters(bool disable_empty,
80 const DisableInterrupts &) {
81 while (true) {
82 if (buffer_.empty()) {
83 if (disable_empty) {
84 uart_.DisableTransmitInterrupt();
85 }
86 return;
87 }
88 if (!uart_.SpaceAvailable()) {
89 return;
90 }
91 uart_.WriteCharacter(buffer_.PopSingle());
92 }
93}
94
95} // namespace teensy
96} // namespace frc971