1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
17 #include "pw_preprocessor/compiler.h"
18 #include "pw_sys_io/sys_io.h"
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;
27 constexpr uint32_t kTxFifoEmptyMask = 0b10000000;
28 constexpr uint32_t kRxFifoFullMask = 0b100000;
30 // UART line control flags.
32 constexpr uint32_t kDefaultLineControl = 0x60;
34 // UART control flags.
35 constexpr uint32_t kUartEnableMask = 0x1;
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;
44 uint32_t integer_baud;
45 uint32_t fractional_baud;
46 uint32_t line_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;
55 // Declare a reference to the memory mapped block for UART0.
56 volatile UartBlock& uart0 = *reinterpret_cast<volatile UartBlock*>(0x4000C000U);
58 constexpr uint32_t kRcgcUart0EnableMask = 0x1;
59 volatile uint32_t& rcgc1 = *reinterpret_cast<volatile uint32_t*>(0x400FE104U);
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.
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;
72 extern "C" void pw_sys_io_Init() {
73 rcgc1 |= kRcgcUart0EnableMask;
74 for (volatile int i = 0; i < 3; ++i) {
75 // We must wait after enabling uart.
78 SetBaudRate(kSystemCoreClock, /*target_baud=*/115200);
79 uart0.line_control = kDefaultLineControl;
80 uart0.control |= kUartEnableMask;
83 namespace pw::sys_io {
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.
88 Status ReadByte(std::byte* dest) {
90 if (TryReadByte(dest).ok()) {
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;
101 if (!(uart0.status_flags & kRxFifoFullMask)) {
102 return Status::Unavailable();
104 *dest = static_cast<std::byte>(uart0.data_register);
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
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)) {
117 uart0.data_register = static_cast<uint32_t>(b);
121 // Writes a string using pw::sys_io, and add newline characters at the end.
122 StatusWithSize WriteLine(const std::string_view& s) {
123 size_t chars_written = 0;
124 StatusWithSize result = WriteBytes(std::as_bytes(std::span(s)));
128 chars_written += result.size();
130 // Write trailing newline.
131 result = WriteBytes(std::as_bytes(std::span("\r\n", 2)));
132 chars_written += result.size();
134 return StatusWithSize(result.status(), chars_written);
137 } // namespace pw::sys_io