1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include <cinttypes>
16
17 #include "pw_preprocessor/compiler.h"
18 #include "pw_sys_io/sys_io.h"
19
20 namespace {
21
22 // Default core clock. This is technically not a constant, but since this app
23 // doesn't change the system clock a constant will suffice.
24 constexpr uint32_t kSystemCoreClock = 12000000;
25
26 // UART status flags.
27 constexpr uint32_t kTxFifoEmptyMask = 0b10000000;
28 constexpr uint32_t kRxFifoFullMask = 0b100000;
29
30 // UART line control flags.
31 // Default: 8n1
32 constexpr uint32_t kDefaultLineControl = 0x60;
33
34 // UART control flags.
35 constexpr uint32_t kUartEnableMask = 0x1;
36
PW_PACKED(struct)37 PW_PACKED(struct) UartBlock {
38 uint32_t data_register;
39 uint32_t receive_error;
40 uint32_t reserved1[4];
41 uint32_t status_flags;
42 uint32_t reserved2;
43 uint32_t low_power;
44 uint32_t integer_baud;
45 uint32_t fractional_baud;
46 uint32_t line_control;
47 uint32_t control;
48 uint32_t interrupt_fifo_level;
49 uint32_t interrupt_mask;
50 uint32_t raw_interrupt;
51 uint32_t masked_interrupt;
52 uint32_t interrupt_clear;
53 };
54
55 // Declare a reference to the memory mapped block for UART0.
56 volatile UartBlock& uart0 = *reinterpret_cast<volatile UartBlock*>(0x4000C000U);
57
58 constexpr uint32_t kRcgcUart0EnableMask = 0x1;
59 volatile uint32_t& rcgc1 = *reinterpret_cast<volatile uint32_t*>(0x400FE104U);
60
61 // Calculate a baud rate multiplier such that we have 16 bits of precision for
62 // the integer portion and 6 bits for the fractional portion.
SetBaudRate(uint32_t clock,uint32_t target_baud)63 void SetBaudRate(uint32_t clock, uint32_t target_baud) {
64 uint32_t divisor = target_baud * 16;
65 uint32_t remainder = clock % divisor;
66 uart0.integer_baud = (clock % divisor) & 0xffff;
67 uart0.fractional_baud = (((remainder << 7) / divisor + 1) >> 1) & 0x3f;
68 }
69
70 } // namespace
71
pw_sys_io_lm3s6965evb_Init()72 extern "C" void pw_sys_io_lm3s6965evb_Init() {
73 rcgc1 |= kRcgcUart0EnableMask;
74 for (volatile int i = 0; i < 3; ++i) {
75 // We must wait after enabling uart.
76 }
77 // Set baud rate.
78 SetBaudRate(kSystemCoreClock, /*target_baud=*/115200);
79 uart0.line_control = kDefaultLineControl;
80 uart0.control |= kUartEnableMask;
81 }
82
83 namespace pw::sys_io {
84
85 // Wait for a byte to read on UART0. This blocks until a byte is read. This is
86 // extremely inefficient as it requires the target to burn CPU cycles polling to
87 // see if a byte is ready yet.
ReadByte(std::byte * dest)88 Status ReadByte(std::byte* dest) {
89 while (true) {
90 if (TryReadByte(dest).ok()) {
91 return OkStatus();
92 }
93 }
94 }
95
TryReadByte(std::byte * dest)96 Status TryReadByte(std::byte* dest) {
97 if (uart0.receive_error) {
98 // Writing anything to this register clears all errors.
99 uart0.receive_error = 0xff;
100 }
101 if (!(uart0.status_flags & kRxFifoFullMask)) {
102 return Status::Unavailable();
103 }
104 *dest = static_cast<std::byte>(uart0.data_register);
105 return OkStatus();
106 }
107
108 // Send a byte over UART0. Since this blocks on every byte, it's rather
109 // inefficient. At the default baud rate of 115200, one byte blocks the CPU for
110 // ~87 micro seconds. This means it takes only 10 bytes to block the CPU for
111 // 1ms!
WriteByte(std::byte b)112 Status WriteByte(std::byte b) {
113 // Wait for TX buffer to be empty. When the buffer is empty, we can write
114 // a value to be dumped out of UART.
115 while (!(uart0.status_flags & kTxFifoEmptyMask)) {
116 }
117 uart0.data_register = static_cast<uint32_t>(b);
118 return OkStatus();
119 }
120
121 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(const std::string_view & s)122 StatusWithSize WriteLine(const std::string_view& s) {
123 size_t chars_written = 0;
124 StatusWithSize result = WriteBytes(std::as_bytes(std::span(s)));
125 if (!result.ok()) {
126 return result;
127 }
128 chars_written += result.size();
129
130 // Write trailing newline.
131 result = WriteBytes(std::as_bytes(std::span("\r\n", 2)));
132 chars_written += result.size();
133
134 return StatusWithSize(result.status(), chars_written);
135 }
136
137 } // namespace pw::sys_io
138