/* * Copyright (c) 2025 Joel Guittet * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT zephyr_uart_bitbang #define LOG_LEVEL CONFIG_UART_LOG_LEVEL #include LOG_MODULE_REGISTER(uart_bitbang); #include #include #include #include #include #include enum uart_bitbang_state { UART_BITBANG_IDLE, UART_BITBANG_START_BIT, UART_BITBANG_DATA, UART_BITBANG_PARITY, UART_BITBANG_STOP_BIT_1, UART_BITBANG_STOP_BIT_2, UART_BITBANG_COMPLETE, }; struct uart_bitbang_config { /* GPIOs */ struct gpio_dt_spec tx_gpio; struct gpio_dt_spec rx_gpio; struct gpio_dt_spec de_gpio; /* Counters */ const struct device *tx_counter; const struct device *rx_counter; /* UART config */ struct uart_config *uart_cfg; /* MSB first */ bool msb; }; struct uart_bitbang_data { /* Configuration */ struct uart_bitbang_config *config; /* Error flags */ int err; /* Tx state */ enum uart_bitbang_state tx_state; /* Tx bit index */ int tx_index; /* Tx data */ uint16_t *tx_data; /* Tx parity */ int tx_parity; /* Tx counter config */ struct counter_top_cfg tx_counter_cfg; /* Tx ring buffer */ struct ring_buf *tx_ringbuf; /* Rx state */ enum uart_bitbang_state rx_state; /* Rx bit index */ int rx_index; /* Rx data */ uint16_t rx_data; /* Rx parity */ int rx_parity; /* Rx counter config */ struct counter_top_cfg rx_counter_cfg; /* Rx callback data */ struct gpio_callback rx_gpio_cb_data; /* Rx ring buffer */ struct ring_buf *rx_ringbuf; #ifdef CONFIG_UART_INTERRUPT_DRIVEN /* Interrupt flags */ #define UART_BITBANG_IRQ_TC (1 << 0) #define UART_BITBANG_IRQ_RXNE (1 << 1) #define UART_BITBANG_IRQ_PE (1 << 2) int irq; /* User callback and data */ uart_irq_callback_user_data_t user_cb; void *user_data; #endif }; static int uart_bitbang_init(const struct device *dev); static inline uint8_t uart_bitbang_data_bits_to_len(uint8_t data_bits) { switch (data_bits) { case UART_CFG_DATA_BITS_5: return 5; case UART_CFG_DATA_BITS_6: return 6; case UART_CFG_DATA_BITS_7: return 7; case UART_CFG_DATA_BITS_8: return 8; case UART_CFG_DATA_BITS_9: return 9; } return 0; } static int uart_bitbang_compute_parity(const struct device *dev, uint16_t data_u16) { const struct uart_bitbang_config *config = dev->config; uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits); int parity = 0, index; if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) { for (index = 0; index < len; index++) { const int shift = config->msb ? (len - 1 - index) : index; const int d = (data_u16 >> shift) & 0x1; parity += d; } if (config->uart_cfg->parity == UART_CFG_PARITY_ODD) { parity = (parity % 2) ? 0 : 1; } else if (config->uart_cfg->parity == UART_CFG_PARITY_EVEN) { parity = (parity % 2) ? 1 : 0; } else if (config->uart_cfg->parity == UART_CFG_PARITY_MARK) { parity = 1; } else if (config->uart_cfg->parity == UART_CFG_PARITY_SPACE) { parity = 0; } } return parity; } /* * To perform reception of data, a counter interrupt is used for each bit to be read. * This interrupt uses a state machine and gets the rx gpio depending of the current state. */ static void uart_bitbang_rx_counter_top_interrupt(const struct device *dev, void *user_data) { const struct device *uart_dev = (struct device *)user_data; const struct uart_bitbang_config *config = uart_dev->config; struct uart_bitbang_data *data = uart_dev->data; uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits); int rc; /* Rx state machine */ if (data->rx_state == UART_BITBANG_DATA) { /* Compute rx data depending of the bit index */ const int shift = config->msb ? (len - 1 - data->rx_index) : data->rx_index; data->rx_data |= ((gpio_pin_get_dt(&config->rx_gpio) & 0x1) << shift); data->rx_index++; if (data->rx_index == len) { if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) { data->rx_state = UART_BITBANG_PARITY; } else { data->rx_state = UART_BITBANG_COMPLETE; } } } else if (data->rx_state == UART_BITBANG_PARITY) { /* Read parity bit value */ data->rx_parity = gpio_pin_get_dt(&config->rx_gpio); data->rx_state = UART_BITBANG_COMPLETE; } /* Intentional fall-through */ if (data->rx_state == UART_BITBANG_COMPLETE) { /* Stop rx counter */ counter_stop(config->rx_counter); data->rx_state = UART_BITBANG_IDLE; /* Enable rx gpio interrupt */ rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_EDGE_FALLING); if (rc < 0) { LOG_ERR("Couldn't configure rx pin (%d)", rc); } /* Check parity */ if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) { if (data->rx_parity != uart_bitbang_compute_parity(uart_dev, data->rx_data)) { /* Indicate parity error */ data->err |= UART_ERROR_PARITY; #ifdef CONFIG_UART_INTERRUPT_DRIVEN if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_PE)) { data->user_cb(dev, data->user_data); } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ return; } } /* Push data received to rx ring buffer */ ring_buf_put(data->rx_ringbuf, (const uint8_t *)&data->rx_data, sizeof(uint16_t)); #ifdef CONFIG_UART_INTERRUPT_DRIVEN if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_RXNE)) { data->user_cb(dev, data->user_data); } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ } } static void uart_bitbang_rx_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { struct uart_bitbang_data *data = CONTAINER_OF(cb, struct uart_bitbang_data, rx_gpio_cb_data); struct uart_bitbang_config *config = data->config; (void)pins; int rc; /* Start bit detected, start reception of data */ data->rx_data = 0; data->rx_index = 0; data->rx_state = UART_BITBANG_DATA; counter_reset(config->rx_counter); counter_start(config->rx_counter); /* Disable rx gpio interrupt */ rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_DISABLE); if (rc < 0) { LOG_ERR("Couldn't configure rx pin (%d)", rc); } } static int uart_bitbang_poll_in_u16(const struct device *dev, uint16_t *in_u16) { struct uart_bitbang_data *data = dev->data; uint32_t s = ring_buf_get(data->rx_ringbuf, (uint8_t *)in_u16, sizeof(uint16_t)); return (s == sizeof(uint16_t)) ? 0 : -1; } static int uart_bitbang_poll_in(const struct device *dev, unsigned char *c) { uint16_t in_u16; int rc; rc = uart_bitbang_poll_in_u16(dev, &in_u16); *c = (unsigned char)(in_u16 & 0xFF); return rc; } /* * To perform transmission of data, a counter interrupt is used for each bit to be transmitted. * This interrupt uses a state machine and sets the tx gpio depending of the current state. */ static void uart_bitbang_tx_counter_top_interrupt(const struct device *dev, void *user_data) { const struct device *uart_dev = (struct device *)user_data; const struct uart_bitbang_config *config = uart_dev->config; struct uart_bitbang_data *data = uart_dev->data; uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits); uint32_t size; /* Tx state machine */ switch (data->tx_state) { case UART_BITBANG_IDLE: /* Claim the next data */ size = ring_buf_get_claim(data->tx_ringbuf, (uint8_t **)&data->tx_data, sizeof(uint16_t)); if (size == sizeof(uint16_t)) { /* Start next transmission */ data->tx_index = 0; data->tx_parity = uart_bitbang_compute_parity(uart_dev, *data->tx_data); data->tx_state = UART_BITBANG_START_BIT; /* Assert RS485 driver enable pin */ if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) && (config->de_gpio.port != NULL)) { gpio_pin_set_dt(&config->de_gpio, 1); } } else { /* End of the transmission, stop tx counter */ counter_stop(config->tx_counter); /* Release RS485 driver enable pin */ if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) && (config->de_gpio.port != NULL)) { gpio_pin_set_dt(&config->de_gpio, 0); } #ifdef CONFIG_UART_INTERRUPT_DRIVEN if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_TC)) { data->user_cb(dev, data->user_data); } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ } break; case UART_BITBANG_START_BIT: /* Set start bit value */ gpio_pin_set_dt(&config->tx_gpio, 0); /* Prepare transmission of data */ data->tx_state = UART_BITBANG_DATA; break; case UART_BITBANG_DATA: /* Set tx gpio depending of the bit index */ const int shift = config->msb ? (len - 1 - data->tx_index) : data->tx_index; const int d = (*data->tx_data >> shift) & 0x1; gpio_pin_set_dt(&config->tx_gpio, d); data->tx_index++; if (data->tx_index == len) { if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) { data->tx_state = UART_BITBANG_PARITY; } else { data->tx_state = UART_BITBANG_STOP_BIT_1; } } break; case UART_BITBANG_PARITY: /* Set parity bit value */ gpio_pin_set_dt(&config->tx_gpio, data->tx_parity); data->tx_state = UART_BITBANG_STOP_BIT_1; break; case UART_BITBANG_STOP_BIT_1: /* Set stop bit value */ gpio_pin_set_dt(&config->tx_gpio, 1); if (config->uart_cfg->stop_bits > UART_CFG_STOP_BITS_1) { data->tx_state = UART_BITBANG_STOP_BIT_2; } else { data->tx_state = UART_BITBANG_COMPLETE; } break; case UART_BITBANG_STOP_BIT_2: /* Wait one more bit in case 1.5 or 2 stop bits */ data->tx_state = UART_BITBANG_COMPLETE; break; case UART_BITBANG_COMPLETE: /* Terminate current transfer */ ring_buf_get_finish(data->tx_ringbuf, sizeof(uint16_t)); data->tx_state = UART_BITBANG_IDLE; break; } } static void uart_bitbang_poll_out_u16(const struct device *dev, uint16_t out_u16) { const struct uart_bitbang_config *config = dev->config; struct uart_bitbang_data *data = dev->data; /* Transmit data */ if (config->tx_gpio.port != NULL) { /* Push data to send to tx ring buffer */ ring_buf_put(data->tx_ringbuf, (const uint8_t *)&out_u16, sizeof(uint16_t)); /* Start tx counter if not already started */ counter_reset(config->tx_counter); counter_start(config->tx_counter); } } static void uart_bitbang_poll_out(const struct device *dev, unsigned char c) { uart_bitbang_poll_out_u16(dev, (uint16_t)c); } /* * Handler used when tx and rx counters are the same instance (half-duplex communications). * The tx or rx handler is called depending on the device state (rx state not idle indicating the * reception of data). */ static void uart_bitbang_tx_rx_counter_top_interrupt(const struct device *dev, void *user_data) { const struct device *uart_dev = (struct device *)user_data; struct uart_bitbang_data *data = uart_dev->data; if (data->rx_state != UART_BITBANG_IDLE) { uart_bitbang_rx_counter_top_interrupt(dev, user_data); } else { uart_bitbang_tx_counter_top_interrupt(dev, user_data); } } static int uart_bitbang_err_check(const struct device *dev) { struct uart_bitbang_data *data = dev->data; int err; /* Check for errors, then clear them */ err = data->err; data->err = 0; return err; } #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE static int uart_bitbang_configure(const struct device *dev, const struct uart_config *cfg) { const struct uart_bitbang_config *config = dev->config; /* Copy configuration */ memcpy(config->uart_cfg, cfg, sizeof(struct uart_config)); /* Reinitialize device */ return uart_bitbang_init(dev); }; static int uart_bitbang_config_get(const struct device *dev, struct uart_config *cfg) { const struct uart_bitbang_config *config = dev->config; /* Copy configuration */ memcpy(cfg, config->uart_cfg, sizeof(struct uart_config)); return 0; } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN static int uart_bitbang_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) { int index = 0; while (size - index > 0) { uart_bitbang_poll_out(dev, tx_data[index]); index++; } return index; } #ifdef CONFIG_UART_WIDE_DATA static int uart_bitbang_fifo_fill_u16(const struct device *dev, const uint16_t *tx_data, int size) { int index = 0; while (size - index > 0) { uart_bitbang_poll_out_u16(dev, tx_data[index]); index++; } return index; } #endif /* CONFIG_UART_WIDE_DATA */ static int uart_bitbang_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) { int index = 0; while (size - index > 0) { if (uart_bitbang_poll_in(dev, &rx_data[index]) < 0) { break; } index++; } return index; } #ifdef CONFIG_UART_WIDE_DATA static int uart_bitbang_fifo_read_u16(const struct device *dev, uint16_t *rx_data, const int size) { int index = 0; while (size - index > 0) { if (uart_bitbang_poll_in_u16(dev, &rx_data[index]) < 0) { break; } index++; } return index; } #endif /* CONFIG_UART_WIDE_DATA */ static void uart_bitbang_irq_tx_enable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Enable Transmission Complete interrupt */ data->irq |= UART_BITBANG_IRQ_TC; } static void uart_bitbang_irq_tx_disable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Disable Transmission Complete interrupt */ data->irq &= ~UART_BITBANG_IRQ_TC; } static int uart_bitbang_irq_tx_ready(const struct device *dev) { struct uart_bitbang_data *data = dev->data; return (int)(ring_buf_space_get(data->tx_ringbuf) / sizeof(uint16_t)); } static void uart_bitbang_irq_rx_enable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Enable Receive data register Not Empty interrupt */ data->irq |= UART_BITBANG_IRQ_RXNE; } static void uart_bitbang_irq_rx_disable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Disable Receive data register Not Empty interrupt */ data->irq &= ~UART_BITBANG_IRQ_RXNE; } static int uart_bitbang_irq_tx_complete(const struct device *dev) { struct uart_bitbang_data *data = dev->data; return ring_buf_is_empty(data->tx_ringbuf) ? 1 : 0; } static int uart_bitbang_irq_rx_ready(const struct device *dev) { struct uart_bitbang_data *data = dev->data; return (ring_buf_size_get(data->rx_ringbuf) > 0) ? 1 : 0; } static void uart_bitbang_irq_err_enable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Enable Parity Error interrupt */ data->irq |= UART_BITBANG_IRQ_PE; } static void uart_bitbang_irq_err_disable(const struct device *dev) { struct uart_bitbang_data *data = dev->data; /* Disable Parity Error interrupt */ data->irq &= ~UART_BITBANG_IRQ_PE; } static int uart_bitbang_irq_is_pending(const struct device *dev) { return 0; } static int uart_bitbang_irq_update(const struct device *dev) { return 1; } static void uart_bitbang_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *cb_data) { struct uart_bitbang_data *data = dev->data; data->user_cb = cb; data->user_data = cb_data; } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ static DEVICE_API(uart, uart_bitbang_api) = { .poll_in = uart_bitbang_poll_in, .poll_out = uart_bitbang_poll_out, #ifdef CONFIG_UART_WIDE_DATA .poll_in_u16 = uart_bitbang_poll_in_u16, .poll_out_u16 = uart_bitbang_poll_out_u16, #endif /* CONFIG_UART_WIDE_DATA */ .err_check = uart_bitbang_err_check, #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = uart_bitbang_configure, .config_get = uart_bitbang_config_get, #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_bitbang_fifo_fill, #ifdef CONFIG_UART_WIDE_DATA .fifo_fill_u16 = uart_bitbang_fifo_fill_u16, #endif /* CONFIG_UART_WIDE_DATA */ .fifo_read = uart_bitbang_fifo_read, #ifdef CONFIG_UART_WIDE_DATA .fifo_read_u16 = uart_bitbang_fifo_read_u16, #endif /* CONFIG_UART_WIDE_DATA */ .irq_tx_enable = uart_bitbang_irq_tx_enable, .irq_tx_disable = uart_bitbang_irq_tx_disable, .irq_tx_ready = uart_bitbang_irq_tx_ready, .irq_rx_enable = uart_bitbang_irq_rx_enable, .irq_rx_disable = uart_bitbang_irq_rx_disable, .irq_tx_complete = uart_bitbang_irq_tx_complete, .irq_rx_ready = uart_bitbang_irq_rx_ready, .irq_err_enable = uart_bitbang_irq_err_enable, .irq_err_disable = uart_bitbang_irq_err_disable, .irq_is_pending = uart_bitbang_irq_is_pending, .irq_update = uart_bitbang_irq_update, .irq_callback_set = uart_bitbang_irq_callback_set, #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; static int uart_bitbang_init(const struct device *dev) { const struct uart_bitbang_config *config = dev->config; struct uart_bitbang_data *data = dev->data; int rc; /* Initialize tx state */ data->tx_state = UART_BITBANG_IDLE; /* * Setup tx counter so that the counter interrupts for each bit to be generated * A state machine in the interrupt handler permits to generate the uart signal */ if (config->tx_gpio.port != NULL) { if (config->tx_counter == NULL) { LOG_ERR("Couldn't configure tx counter"); return -ENODEV; } else if (config->tx_counter != config->rx_counter) { if (!device_is_ready(config->tx_counter)) { LOG_ERR("Couldn't configure tx counter"); return -ENODEV; } data->tx_counter_cfg.callback = uart_bitbang_tx_counter_top_interrupt; data->tx_counter_cfg.ticks = counter_get_frequency(config->tx_counter) / config->uart_cfg->baudrate; data->tx_counter_cfg.user_data = (void *)dev; data->tx_counter_cfg.flags = 0; rc = counter_set_top_value(config->tx_counter, &data->tx_counter_cfg); if (rc < 0) { LOG_ERR("Couldn't configure tx counter (%d)", rc); return rc; } } } /* Initialize rx state */ data->rx_state = UART_BITBANG_IDLE; /* * Setup rx counter so that the counter interrupts for each bit to be read * A state machine in the interrupt handler permits to capture the uart signal */ if (config->rx_gpio.port != NULL) { if (config->rx_counter == NULL) { LOG_ERR("Couldn't configure rx counter"); return -ENODEV; } else if (config->rx_counter != config->tx_counter) { if (!device_is_ready(config->rx_counter)) { LOG_ERR("Couldn't configure rx counter"); return -ENODEV; } data->rx_counter_cfg.callback = uart_bitbang_rx_counter_top_interrupt; data->rx_counter_cfg.ticks = counter_get_frequency(config->rx_counter) / config->uart_cfg->baudrate; data->rx_counter_cfg.user_data = (void *)dev; data->rx_counter_cfg.flags = 0; rc = counter_set_top_value(config->rx_counter, &data->rx_counter_cfg); if (rc < 0) { LOG_ERR("Couldn't configure rx counter (%d)", rc); return rc; } } } /* * Setup tx/rx counter in case it is the same instance so that the counter interrupts for * each bit to be generated or read * The interrupt handler calls the tx or rx counter handler depending on the device state */ if (((config->tx_gpio.port != NULL) || (config->rx_gpio.port != NULL)) && (config->tx_counter != NULL) && (config->tx_counter == config->rx_counter)) { if (!device_is_ready(config->tx_counter)) { LOG_ERR("Couldn't configure tx/rx counter"); return -ENODEV; } data->tx_counter_cfg.callback = uart_bitbang_tx_rx_counter_top_interrupt; data->tx_counter_cfg.ticks = counter_get_frequency(config->tx_counter) / config->uart_cfg->baudrate; data->tx_counter_cfg.user_data = (void *)dev; data->tx_counter_cfg.flags = 0; rc = counter_set_top_value(config->tx_counter, &data->tx_counter_cfg); if (rc < 0) { LOG_ERR("Couldn't configure tx/rx counter (%d)", rc); return rc; } } /* Setup tx gpio if it is defined */ if (config->tx_gpio.port != NULL) { if (!gpio_is_ready_dt(&config->tx_gpio)) { LOG_ERR("GPIO port for tx pin is not ready"); return -ENODEV; } rc = gpio_pin_configure_dt(&config->tx_gpio, GPIO_OUTPUT_INACTIVE); if (rc < 0) { LOG_ERR("Couldn't configure tx pin (%d)", rc); return rc; } rc = gpio_pin_set_dt(&config->tx_gpio, 1); if (rc < 0) { LOG_ERR("Couldn't set tx pin (%d)", rc); return rc; } } /* Setup rx gpio if it is defined */ if (config->rx_gpio.port != NULL) { if (!gpio_is_ready_dt(&config->rx_gpio)) { LOG_ERR("GPIO port for rx pin is not ready"); return -ENODEV; } rc = gpio_pin_configure_dt(&config->rx_gpio, GPIO_INPUT); if (rc < 0) { LOG_ERR("Couldn't configure rx pin (%d)", rc); return rc; } rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_EDGE_FALLING); if (rc < 0) { LOG_ERR("Couldn't configure rx pin (%d)", rc); return rc; } gpio_init_callback(&data->rx_gpio_cb_data, uart_bitbang_rx_callback, BIT(config->rx_gpio.pin)); rc = gpio_add_callback_dt(&config->rx_gpio, &data->rx_gpio_cb_data); if (rc < 0) { LOG_ERR("Couldn't configure rx callback (%d)", rc); return rc; } } /* Setup RS485 driver enable gpio if it is defined */ if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) && (config->de_gpio.port != NULL)) { if (!gpio_is_ready_dt(&config->de_gpio)) { LOG_ERR("GPIO port for driver enable pin is not ready"); return -ENODEV; } rc = gpio_pin_configure_dt(&config->de_gpio, GPIO_OUTPUT_INACTIVE); if (rc < 0) { LOG_ERR("Couldn't configure driver enable pin (%d)", rc); return rc; } rc = gpio_pin_set_dt(&config->de_gpio, 0); if (rc < 0) { LOG_ERR("Couldn't set driver enable pin (%d)", rc); return rc; } } return 0; } #define UART_BITBANG_INIT(index) \ static struct uart_config uart_cfg_##index = { \ .baudrate = DT_INST_PROP(index, current_speed), \ .parity = DT_INST_ENUM_IDX(index, parity), \ .stop_bits = DT_INST_ENUM_IDX(index, stop_bits), \ .data_bits = DT_INST_ENUM_IDX(index, data_bits), \ .flow_ctrl = DT_INST_PROP(index, hw_flow_control) ? UART_CFG_FLOW_CTRL_RTS_CTS \ : DT_INST_PROP(index, hw_rs485_flow_control) \ ? UART_CFG_FLOW_CTRL_RS485 \ : UART_CFG_FLOW_CTRL_NONE, \ }; \ static struct uart_bitbang_config uart_bitbang_config_##index = { \ .tx_gpio = GPIO_DT_SPEC_INST_GET_OR(index, tx_gpios, {0}), \ .rx_gpio = GPIO_DT_SPEC_INST_GET_OR(index, rx_gpios, {0}), \ .de_gpio = GPIO_DT_SPEC_INST_GET_OR(index, de_gpios, {0}), \ .tx_counter = DEVICE_DT_GET_OR_NULL( \ DT_CHILD(DT_INST_PHANDLE(index, tx_timer), counter)), \ .rx_counter = DEVICE_DT_GET_OR_NULL( \ DT_CHILD(DT_INST_PHANDLE(index, rx_timer), counter)), \ .uart_cfg = &uart_cfg_##index, \ .msb = DT_INST_PROP_OR(index, msb, false), \ }; \ RING_BUF_DECLARE(uart_bitbang_tx_ringbuf##index, DT_INST_PROP(index, tx_fifo_size)); \ RING_BUF_DECLARE(uart_bitbang_rx_ringbuf##index, DT_INST_PROP(index, rx_fifo_size)); \ static struct uart_bitbang_data uart_bitbang_data_##index = { \ .config = &uart_bitbang_config_##index, \ .tx_ringbuf = &uart_bitbang_tx_ringbuf##index, \ .rx_ringbuf = &uart_bitbang_rx_ringbuf##index, \ }; \ DEVICE_DT_INST_DEFINE(index, uart_bitbang_init, PM_DEVICE_DT_INST_GET(index), \ &uart_bitbang_data_##index, &uart_bitbang_config_##index, \ POST_KERNEL, CONFIG_SERIAL_INIT_PRIORITY, &uart_bitbang_api); DT_INST_FOREACH_STATUS_OKAY(UART_BITBANG_INIT)