1 // Copyright 2022 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 "mss_gpio/mss_gpio.h"
18 #include "mss_uart/mss_uart.h"
19 #include "pw_preprocessor/concat.h"
20 #include "pw_status/status.h"
21 #include "pw_sys_io/sys_io.h"
22 #include "pw_sys_io_emcraft_sf2_private/config.h"
23
24 namespace {
25
26 // LEDs GPIOs
27
28 constexpr mss_gpio_id_t kDs3LedGPIO = MSS_GPIO_1;
29 constexpr mss_gpio_id_t kDs4LEDGPIO = MSS_GPIO_2;
30 constexpr uint32_t kDs3LedMask = MSS_GPIO_1_MASK;
31 constexpr uint32_t kDs4LedMask = MSS_GPIO_2_MASK;
32
33 constexpr uint32_t kReadDataReady = 0x1u;
34
35 } // namespace
36
pw_sys_io_Init()37 extern "C" void pw_sys_io_Init() {
38 // Configure MSS GPIOs.
39 #if SF2_MSS_NO_BOOTLOADER
40 MSS_GPIO_init();
41 #endif
42
43 MSS_GPIO_config(kDs3LedGPIO, MSS_GPIO_OUTPUT_MODE);
44 MSS_GPIO_config(kDs4LEDGPIO, MSS_GPIO_OUTPUT_MODE);
45 // Set LEDs to initial app state
46 MSS_GPIO_set_outputs(MSS_GPIO_get_outputs() | kDs4LedMask);
47
48 // Initialize the UART0 controller (57600, 8N1)
49 // Due to a HW eratta in SF2, we need to run at 57600 for
50 // in-system-programming mode. If we are not upgrading FPGA or flash then we
51 // can use a faster BAUD.
52 MSS_UART_init(
53 &g_mss_uart0,
54 MSS_UART_57600_BAUD,
55 MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT);
56 }
57
58 // This whole implementation is very inefficient because it uses the synchronous
59 // polling UART API and only reads / writes 1 byte at a time.
60 namespace pw::sys_io {
61
ReadByte(std::byte * dest)62 Status ReadByte(std::byte* dest) {
63 while (true) {
64 if (TryReadByte(dest).ok()) {
65 return OkStatus();
66 }
67 }
68 }
69
TryReadByte(std::byte * dest)70 Status TryReadByte(std::byte* dest) {
71 if (!(g_mss_uart0.hw_reg->LSR & kReadDataReady)) {
72 return Status::Unavailable();
73 }
74
75 *dest = static_cast<std::byte>(g_mss_uart0.hw_reg->RBR);
76 return OkStatus();
77 }
78
WriteByte(std::byte b)79 Status WriteByte(std::byte b) {
80 // Wait for TX buffer to be empty. When the buffer is empty, we can write
81 // a value to be dumped out of UART.
82 const uint8_t pbuff = (uint8_t)b;
83
84 MSS_UART_polled_tx(&g_mss_uart0, &pbuff, 1);
85 return OkStatus();
86 }
87
88 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)89 StatusWithSize WriteLine(std::string_view s) {
90 size_t chars_written = 0;
91 StatusWithSize result = WriteBytes(as_bytes(span(s)));
92 if (!result.ok()) {
93 return result;
94 }
95 chars_written += result.size();
96
97 // Write trailing newline.
98 result = WriteBytes(as_bytes(span("\r\n", 2)));
99 chars_written += result.size();
100
101 return StatusWithSize(OkStatus(), chars_written);
102 }
103
104 } // namespace pw::sys_io
105