1 // Copyright 2021 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 "pw_sys_io/sys_io.h"
16
17 #include <cinttypes>
18
19 #include "pw_preprocessor/concat.h"
20 #include "pw_status/status.h"
21 #include "pw_sys_io_stm32cube_private/config.h"
22 #include "stm32cube/stm32cube.h"
23
24 // These macros remap config options to the various STM32Cube HAL macro names.
25
26 // USART_INSTANCE defined to USARTn, where n is the USART peripheral index.
27 #define USART_INSTANCE \
28 PW_CONCAT(PW_SYS_IO_STM32CUBE_USART_PREFIX, PW_SYS_IO_STM32CUBE_USART_NUM)
29
30 // USART_GPIO_ALTERNATE_FUNC defined to GPIO_AFm_USARTn, where m is the
31 // alternate function index and n is the USART peripheral index.
32 #define USART_GPIO_ALTERNATE_FUNC \
33 PW_CONCAT(GPIO_AF, \
34 PW_SYS_IO_STM32CUBE_GPIO_AF, \
35 _, \
36 PW_SYS_IO_STM32CUBE_USART_PREFIX, \
37 PW_SYS_IO_STM32CUBE_USART_NUM)
38
39 // USART_GPIO_REMAP defined to __HAL_AFIO_REMAP_USARTn_val,
40 // where n is the USART peripheral index and val is ENABLE or DISABLE.
41 // It only applies to the stm32f1xx family.
42 #define USART_GPIO_REMAP \
43 PW_CONCAT(__HAL_AFIO_REMAP_, \
44 PW_SYS_IO_STM32CUBE_USART_PREFIX, \
45 PW_SYS_IO_STM32CUBE_USART_NUM, \
46 _, \
47 PW_SYS_IO_STM32CUBE_GPIO_REMAP)
48
49 // USART_GPIO_PORT defined to GPIOx, where x is the GPIO port letter that the
50 // TX/RX pins are on.
51 #define USART_GPIO_TX_PORT PW_CONCAT(GPIO, PW_SYS_IO_STM32CUBE_GPIO_TX_PORT)
52 #define USART_GPIO_RX_PORT PW_CONCAT(GPIO, PW_SYS_IO_STM32CUBE_GPIO_RX_PORT)
53 #define USART_GPIO_TX_PIN PW_CONCAT(GPIO_PIN_, PW_SYS_IO_STM32CUBE_GPIO_TX_PIN)
54 #define USART_GPIO_RX_PIN PW_CONCAT(GPIO_PIN_, PW_SYS_IO_STM32CUBE_GPIO_RX_PIN)
55
56 // USART_GPIO_PORT_ENABLE defined to __HAL_RCC_GPIOx_CLK_ENABLE, where x is the
57 // GPIO port letter that the TX/RX pins are on.
58 #define USART_GPIO_TX_PORT_ENABLE \
59 PW_CONCAT(__HAL_RCC_GPIO, PW_SYS_IO_STM32CUBE_GPIO_TX_PORT, _CLK_ENABLE)
60
61 #define USART_GPIO_RX_PORT_ENABLE \
62 PW_CONCAT(__HAL_RCC_GPIO, PW_SYS_IO_STM32CUBE_GPIO_RX_PORT, _CLK_ENABLE)
63
64 // USART_ENABLE defined to __HAL_RCC_USARTn_CLK_ENABLE, where n is the USART
65 // peripheral index.
66 #define USART_ENABLE \
67 PW_CONCAT(__HAL_RCC_, \
68 PW_SYS_IO_STM32CUBE_USART_PREFIX, \
69 PW_SYS_IO_STM32CUBE_USART_NUM, \
70 _CLK_ENABLE)
71
72 static UART_HandleTypeDef uart;
73
pw_sys_io_Init()74 extern "C" void pw_sys_io_Init() {
75 GPIO_InitTypeDef GPIO_InitStruct = {};
76
77 USART_ENABLE();
78 USART_GPIO_TX_PORT_ENABLE();
79 USART_GPIO_RX_PORT_ENABLE();
80 #if defined(STM32F1)
81 __HAL_RCC_AFIO_CLK_ENABLE();
82 #endif // defined(STM32F1)
83
84 GPIO_InitStruct.Pin = USART_GPIO_TX_PIN;
85 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
86 GPIO_InitStruct.Pull = GPIO_NOPULL;
87 #if defined(STM32F0) || defined(STM32F1) || defined(STM32F3)
88 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
89 #else
90 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
91 #endif
92 #if !defined(STM32F1)
93 GPIO_InitStruct.Alternate = USART_GPIO_ALTERNATE_FUNC;
94 #endif // !defined(STM32F1)
95 HAL_GPIO_Init(USART_GPIO_TX_PORT, &GPIO_InitStruct);
96
97 GPIO_InitStruct.Pin = USART_GPIO_RX_PIN;
98 #if defined(STM32F1)
99 GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
100 #else
101 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
102 #endif
103 GPIO_InitStruct.Pull = GPIO_NOPULL;
104 #if defined(STM32F0) || defined(STM32F1) || defined(STM32F3)
105 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
106 #else
107 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
108 #endif
109 #if !defined(STM32F1)
110 GPIO_InitStruct.Alternate = USART_GPIO_ALTERNATE_FUNC;
111 #endif // !defined(STM32F1)
112 HAL_GPIO_Init(USART_GPIO_RX_PORT, &GPIO_InitStruct);
113
114 #if defined(STM32F1)
115 USART_GPIO_REMAP();
116 #endif // defined(STM32F1)
117
118 uart.Instance = USART_INSTANCE;
119 uart.Init.BaudRate = 115200;
120 uart.Init.WordLength = UART_WORDLENGTH_8B;
121 uart.Init.StopBits = UART_STOPBITS_1;
122 uart.Init.Parity = UART_PARITY_NONE;
123 uart.Init.Mode = UART_MODE_TX_RX;
124 uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
125 uart.Init.OverSampling = UART_OVERSAMPLING_16;
126 HAL_UART_Init(&uart);
127 }
128
129 // This whole implementation is very inefficient because it uses the synchronous
130 // polling UART API and only reads / writes 1 byte at a time.
131 namespace pw::sys_io {
ReadByte(std::byte * dest)132 Status ReadByte(std::byte* dest) {
133 if (HAL_UART_Receive(
134 &uart, reinterpret_cast<uint8_t*>(dest), 1, HAL_MAX_DELAY) !=
135 HAL_OK) {
136 return Status::ResourceExhausted();
137 }
138 return OkStatus();
139 }
140
TryReadByte(std::byte * dest)141 Status TryReadByte(std::byte* dest) { return Status::Unimplemented(); }
142
WriteByte(std::byte b)143 Status WriteByte(std::byte b) {
144 if (HAL_UART_Transmit(
145 &uart, reinterpret_cast<uint8_t*>(&b), 1, HAL_MAX_DELAY) != HAL_OK) {
146 return Status::ResourceExhausted();
147 }
148 return OkStatus();
149 }
150
151 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)152 StatusWithSize WriteLine(std::string_view s) {
153 size_t chars_written = 0;
154 StatusWithSize result = WriteBytes(as_bytes(span(s)));
155 if (!result.ok()) {
156 return result;
157 }
158 chars_written += result.size();
159
160 // Write trailing newline.
161 result = WriteBytes(as_bytes(span("\r\n", 2)));
162 chars_written += result.size();
163
164 return StatusWithSize(OkStatus(), chars_written);
165 }
166
167 } // namespace pw::sys_io
168