blob: 3f7ddafd7d2dd4f07e5f557bd859715663c7d0e0 [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
Brian Silverman4787a6e2018-10-06 16:00:54 -070053void Uart::DoWrite(gsl::span<const char> data) {
Brian Silverman55c62022018-09-03 19:13:44 -070054 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
Brian Silverman4787a6e2018-10-06 16:00:54 -070067void InterruptBufferedUart::Write(gsl::span<const char> data) {
Brian Silverman12fec3f2018-09-09 16:09:50 -070068 DisableInterrupts disable_interrupts;
Brian Silverman55c62022018-09-03 19:13:44 -070069 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);
Brian Silverman12fec3f2018-09-09 16:09:50 -070076 ReenableInterrupts{&disable_interrupts};
Brian Silverman55c62022018-09-03 19:13:44 -070077 }
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