// Copyright 2021 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_sys_io/sys_io.h" #include #include "pw_preprocessor/concat.h" #include "pw_status/status.h" #include "pw_sys_io_stm32cube_private/config.h" #include "stm32cube/stm32cube.h" // These macros remap config options to the various STM32Cube HAL macro names. // USART_INSTANCE defined to USARTn, where n is the USART peripheral index. #define USART_INSTANCE PW_CONCAT(USART, PW_SYS_IO_STM32CUBE_USART_NUM) // USART_GPIO_ALTERNATE_FUNC defined to GPIO_AFm_USARTn, where m is the // alternate function index and n is the USART peripheral index. #define USART_GPIO_ALTERNATE_FUNC \ PW_CONCAT(GPIO_AF, \ PW_SYS_IO_STM32CUBE_GPIO_AF, \ _USART, \ PW_SYS_IO_STM32CUBE_USART_NUM) // USART_GPIO_PORT defined to GPIOx, where x is the GPIO port letter that the // TX/RX pins are on. #define USART_GPIO_PORT PW_CONCAT(GPIO, PW_SYS_IO_STM32CUBE_GPIO_PORT) #define USART_GPIO_TX_PIN PW_CONCAT(GPIO_PIN_, PW_SYS_IO_STM32CUBE_GPIO_TX_PIN) #define USART_GPIO_RX_PIN PW_CONCAT(GPIO_PIN_, PW_SYS_IO_STM32CUBE_GPIO_RX_PIN) // USART_GPIO_PORT_ENABLE defined to __HAL_RCC_GPIOx_CLK_ENABLE, where x is the // GPIO port letter that the TX/RX pins are on. #define USART_GPIO_PORT_ENABLE \ PW_CONCAT(__HAL_RCC_GPIO, PW_SYS_IO_STM32CUBE_GPIO_PORT, _CLK_ENABLE) // USART_ENABLE defined to __HAL_RCC_USARTn_CLK_ENABLE, where n is the USART // peripheral index. #define USART_ENABLE \ PW_CONCAT(__HAL_RCC_USART, PW_SYS_IO_STM32CUBE_USART_NUM, _CLK_ENABLE) static UART_HandleTypeDef uart; extern "C" void pw_sys_io_Init() { GPIO_InitTypeDef GPIO_InitStruct = {}; USART_ENABLE(); USART_GPIO_PORT_ENABLE(); GPIO_InitStruct.Pin = USART_GPIO_TX_PIN | USART_GPIO_RX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = USART_GPIO_ALTERNATE_FUNC; HAL_GPIO_Init(USART_GPIO_PORT, &GPIO_InitStruct); uart.Instance = USART_INSTANCE; uart.Init.BaudRate = 115200; uart.Init.WordLength = UART_WORDLENGTH_8B; uart.Init.StopBits = UART_STOPBITS_1; uart.Init.Parity = UART_PARITY_NONE; uart.Init.Mode = UART_MODE_TX_RX; uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; uart.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&uart); } // This whole implementation is very inefficient because it uses the synchronous // polling UART API and only reads / writes 1 byte at a time. namespace pw::sys_io { Status ReadByte(std::byte* dest) { if (HAL_UART_Receive( &uart, reinterpret_cast(dest), 1, HAL_MAX_DELAY) != HAL_OK) { return Status::ResourceExhausted(); } return OkStatus(); } Status TryReadByte(std::byte* dest) { return Status::Unimplemented(); } Status WriteByte(std::byte b) { if (HAL_UART_Transmit( &uart, reinterpret_cast(&b), 1, HAL_MAX_DELAY) != HAL_OK) { return Status::ResourceExhausted(); } return OkStatus(); } // Writes a string using pw::sys_io, and add newline characters at the end. StatusWithSize WriteLine(const std::string_view& s) { size_t chars_written = 0; StatusWithSize result = WriteBytes(as_bytes(span(s))); if (!result.ok()) { return result; } chars_written += result.size(); // Write trailing newline. result = WriteBytes(as_bytes(span("\r\n", 2))); chars_written += result.size(); return StatusWithSize(OkStatus(), chars_written); } } // namespace pw::sys_io