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
75 for (volatile int i = 0; i < 3; i = i + 1) {
76 // We must wait after enabling uart.
77 }
78 // Set baud rate.
79 SetBaudRate(kSystemCoreClock, /*target_baud=*/115200);
80 uart0.line_control = kDefaultLineControl;
81 uart0.control |= kUartEnableMask;
82 }
83
84 namespace pw::sys_io {
85
86 // Wait for a byte to read on UART0. This blocks until a byte is read. This is
87 // extremely inefficient as it requires the target to burn CPU cycles polling to
88 // see if a byte is ready yet.
ReadByte(std::byte * dest)89 Status ReadByte(std::byte* dest) {
90 while (true) {
91 if (TryReadByte(dest).ok()) {
92 return OkStatus();
93 }
94 }
95 }
96
TryReadByte(std::byte * dest)97 Status TryReadByte(std::byte* dest) {
98 if (uart0.receive_error) {
99 // Writing anything to this register clears all errors.
100 uart0.receive_error = 0xff;
101 }
102 if (!(uart0.status_flags & kRxFifoFullMask)) {
103 return Status::Unavailable();
104 }
105 *dest = static_cast<std::byte>(uart0.data_register);
106 return OkStatus();
107 }
108
109 // Send a byte over UART0. Since this blocks on every byte, it's rather
110 // inefficient. At the default baud rate of 115200, one byte blocks the CPU for
111 // ~87 micro seconds. This means it takes only 10 bytes to block the CPU for
112 // 1ms!
WriteByte(std::byte b)113 Status WriteByte(std::byte b) {
114 // Wait for TX buffer to be empty. When the buffer is empty, we can write
115 // a value to be dumped out of UART.
116 while (!(uart0.status_flags & kTxFifoEmptyMask)) {
117 }
118 uart0.data_register = static_cast<uint32_t>(b);
119 return OkStatus();
120 }
121
122 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)123 StatusWithSize WriteLine(std::string_view s) {
124 size_t chars_written = 0;
125 StatusWithSize result = WriteBytes(as_bytes(span(s)));
126 if (!result.ok()) {
127 return result;
128 }
129 chars_written += result.size();
130
131 // Write trailing newline.
132 result = WriteBytes(as_bytes(span("\r\n", 2)));
133 chars_written += result.size();
134
135 return StatusWithSize(result.status(), chars_written);
136 }
137
138 } // namespace pw::sys_io
139