#include "uart_driver.h" #include "gd32f4xx.h" #include #include #include #include #include struct uart_hw_config_t { uint32_t uart_base; rcu_periph_enum rcu_clock; uint32_t gpio_port; rcu_periph_enum gpio_rcu; uint32_t tx_pin; uint32_t rx_pin; uint32_t af; }; static constexpr uart_hw_config_t uart_hw_map[] = { {USART0, RCU_USART0, GPIOA, RCU_GPIOA, GPIO_PIN_9, GPIO_PIN_10, GPIO_AF_7}, {USART1, RCU_USART1, GPIOA, RCU_GPIOA, GPIO_PIN_2, GPIO_PIN_3, GPIO_AF_7}, {USART2, RCU_USART2, GPIOB, RCU_GPIOB, GPIO_PIN_10, GPIO_PIN_11, GPIO_AF_7}, {UART3, RCU_UART3, GPIOC, RCU_GPIOC, GPIO_PIN_10, GPIO_PIN_11, GPIO_AF_7}, {UART4, RCU_UART4, GPIOC, RCU_GPIOC, GPIO_PIN_12, GPIO_PIN_2, GPIO_AF_7}, {USART5, RCU_USART5, GPIOD, RCU_GPIOD, GPIO_PIN_2, GPIO_PIN_3, GPIO_AF_7}, {UART6, RCU_UART6, GPIOG, RCU_GPIOG, GPIO_PIN_6, GPIO_PIN_7, GPIO_AF_7}, }; USART *USART::default_ = nullptr; USART::USART(UartPort port, uint32_t baudrate) : port_(port), baudrate_(baudrate) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(uart_hw_map) / sizeof(uart_hw_map[0])) { return; } const uart_hw_config_t &hw = uart_hw_map[port_idx]; if (hw.uart_base == 0) { return; } rcu_periph_clock_enable(hw.rcu_clock); rcu_periph_clock_enable(hw.gpio_rcu); gpio_af_set(hw.gpio_port, hw.af, hw.tx_pin | hw.rx_pin); gpio_mode_set(hw.gpio_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, hw.tx_pin | hw.rx_pin); gpio_output_options_set(hw.gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, hw.tx_pin | hw.rx_pin); usart_deinit(hw.uart_base); usart_baudrate_set(hw.uart_base, baudrate_); usart_receive_config(hw.uart_base, USART_RECEIVE_ENABLE); usart_transmit_config(hw.uart_base, USART_TRANSMIT_ENABLE); usart_enable(hw.uart_base); initialized_ = true; } USART::~USART() { if (initialized_) { uint8_t port_idx = static_cast(port_); if (port_idx < sizeof(uart_hw_map) / sizeof(uart_hw_map[0])) { usart_disable(uart_hw_map[port_idx].uart_base); } initialized_ = false; } if (default_ == this) { default_ = nullptr; } } RetCode USART::send_byte(uint8_t data) { if (!initialized_) return RET_NOT_INITIALIZED; uint8_t port_idx = static_cast(port_); const uart_hw_config_t &hw = uart_hw_map[port_idx]; while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_TBE)); usart_data_transmit(hw.uart_base, data); while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_TC)); return RET_OK; } RetCode USART::send_data(const uint8_t *data, uint32_t len) { if (!initialized_) return RET_NOT_INITIALIZED; if (data == nullptr || len == 0) return RET_INVALID_PARAM; uint8_t port_idx = static_cast(port_); const uart_hw_config_t &hw = uart_hw_map[port_idx]; for (uint32_t i = 0; i < len; i++) { while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_TBE)); usart_data_transmit(hw.uart_base, data[i]); } while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_TC)); return RET_OK; } RetCode USART::receive_byte(uint8_t *data, uint32_t timeout_ms) { if (!initialized_) return RET_NOT_INITIALIZED; if (data == nullptr) return RET_INVALID_PARAM; uint8_t port_idx = static_cast(port_); const uart_hw_config_t &hw = uart_hw_map[port_idx]; if (timeout_ms == 0) { while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_RBNE)); *data = static_cast(usart_data_receive(hw.uart_base)); return RET_OK; } uint32_t timeout = timeout_ms * 10000; while (RESET == usart_flag_get(hw.uart_base, USART_FLAG_RBNE)) { if (--timeout == 0) { return RET_TIMEOUT; } } *data = static_cast(usart_data_receive(hw.uart_base)); return RET_OK; } void USART::reinit(uint32_t baudrate) { if (!initialized_) return; uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(uart_hw_map) / sizeof(uart_hw_map[0])) return; const uart_hw_config_t &hw = uart_hw_map[port_idx]; baudrate_ = baudrate; usart_disable(hw.uart_base); usart_baudrate_set(hw.uart_base, baudrate_); usart_enable(hw.uart_base); } void USART::setDefault(USART *uart) { default_ = uart; } extern "C" int _write(int file, char *ptr, int len) { if (file == STDOUT_FILENO || file == STDERR_FILENO) { USART *uart = USART::defaultInstance(); if (uart) { uart->send_data(reinterpret_cast(ptr), static_cast(len)); } return len; } errno = EBADF; return -1; } extern "C" int _read(int file, char *ptr, int len) { (void)file; (void)ptr; (void)len; errno = ENOSYS; return -1; } extern "C" int _close(int file) { (void)file; return -1; } extern "C" off_t _lseek(int file, off_t ptr, int dir) { (void)file; (void)ptr; (void)dir; return 0; } extern "C" int _fstat(int file, struct stat *st) { (void)file; st->st_mode = S_IFCHR; return 0; } extern "C" int _isatty(int file) { if (file == STDOUT_FILENO || file == STDERR_FILENO || file == STDIN_FILENO) { return 1; } return 0; } extern "C" int _getpid(void) { return 1; } extern "C" int _kill(int pid, int sig) { (void)pid; (void)sig; errno = EINVAL; return -1; } extern "C" void _exit(int status) { (void)status; while (1); } /* USART global instances */ USART uart_0(UartPort::_0); USART uart_1(UartPort::_1); static USART uart_2(UartPort::_2); static USART uart_3(UartPort::_3); static USART uart_4(UartPort::_4); static USART uart_5(UartPort::_5); static USART uart_6(UartPort::_6); static USART *uart_instances[] = { &uart_0, &uart_1, &uart_2, &uart_3, &uart_4, &uart_5, &uart_6, }; static uint8_t uart_inited[7] = {0}; /* C-compatible wrappers for legacy code */ extern "C" { int uart_init(uint8_t port, uint32_t baudrate) { if (port >= 7) return -1; uart_inited[port] = 1; return 0; } int uart_send_byte(uint8_t port, uint8_t data) { if (port >= 7 || !uart_inited[port]) return -1; return uart_instances[port]->send_byte(data) == RET_OK ? 0 : -1; } int uart_send_data(uint8_t port, const uint8_t *data, uint32_t len) { if (port >= 7 || !uart_inited[port]) return -1; return uart_instances[port]->send_data(data, len) == RET_OK ? 0 : -1; } int uart_receive_byte(uint8_t port, uint8_t *data, uint32_t timeout_ms) { if (port >= 7 || !uart_inited[port]) return -1; return uart_instances[port]->receive_byte(data, timeout_ms) == RET_OK ? 0 : -1; } } /* extern "C" */