diff --git a/dts/bindings/misc/zephyr,modbus-serial.yaml b/dts/bindings/misc/zephyr,modbus-serial.yaml index e761f220e6a..a79736b3b12 100644 --- a/dts/bindings/misc/zephyr,modbus-serial.yaml +++ b/dts/bindings/misc/zephyr,modbus-serial.yaml @@ -6,3 +6,22 @@ description: Modbus over serial line device compatible: "zephyr,modbus-serial" include: uart-device.yaml + +properties: + de-gpios: + type: phandle-array + required: false + description: Driver enable pin. + + Driver enable pin (DE) of the RS-485 transceiver. + If connected directly the MCU pin should be configured + as active high. + + re-gpios: + type: phandle-array + required: false + description: Receiver enable pin. + + Receiver enable pin (nRE) of the RS-485 transceiver. + If connected directly the MCU pin should be configured + as active low. diff --git a/subsys/modbus/mb_rtu_core.c b/subsys/modbus/mb_rtu_core.c index 5a7e4c70a36..1c21da7d1a8 100644 --- a/subsys/modbus/mb_rtu_core.c +++ b/subsys/modbus/mb_rtu_core.c @@ -29,12 +29,69 @@ LOG_MODULE_REGISTER(mb_rtu, CONFIG_MODBUS_RTU_LOG_LEVEL); #define DT_DRV_COMPAT zephyr_modbus_serial -#define MODBUS_DT_GET_DEV(port) {.dev_name = DT_INST_BUS_LABEL(port),}, +#define MB_RTU_DEFINE_GPIO_CFG(n, d) \ + static struct mb_rtu_gpio_config d##_cfg_##n = { \ + .name = DT_INST_GPIO_LABEL(n, d), \ + .pin = DT_INST_GPIO_PIN(n, d), \ + .flags = DT_INST_GPIO_FLAGS(n, d), \ + }; + +#define MB_RTU_DEFINE_GPIO_CFGS(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, de_gpios), \ + (MB_RTU_DEFINE_GPIO_CFG(n, de_gpios)), ()) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, re_gpios), \ + (MB_RTU_DEFINE_GPIO_CFG(n, re_gpios)), ()) + +DT_INST_FOREACH_STATUS_OKAY(MB_RTU_DEFINE_GPIO_CFGS) + +#define MB_RTU_ASSIGN_GPIO_CFG(n, d) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, d), \ + (&d##_cfg_##n), (NULL)) + +#define MODBUS_DT_GET_DEV(n) { \ + .dev_name = DT_INST_BUS_LABEL(n), \ + .de = MB_RTU_ASSIGN_GPIO_CFG(n, de_gpios), \ + .re = MB_RTU_ASSIGN_GPIO_CFG(n, re_gpios), \ + }, static struct mb_rtu_context mb_ctx_tbl[] = { DT_INST_FOREACH_STATUS_OKAY(MODBUS_DT_GET_DEV) }; +static void mb_tx_enable(struct mb_rtu_context *ctx) +{ + if (ctx->de != NULL) { + gpio_pin_set(ctx->de->dev, ctx->de->pin, 1); + } + + uart_irq_tx_enable(ctx->dev); +} + +static void mb_tx_disable(struct mb_rtu_context *ctx) +{ + uart_irq_tx_disable(ctx->dev); + if (ctx->de != NULL) { + gpio_pin_set(ctx->de->dev, ctx->de->pin, 0); + } +} + +static void mb_rx_enable(struct mb_rtu_context *ctx) +{ + if (ctx->re != NULL) { + gpio_pin_set(ctx->re->dev, ctx->re->pin, 1); + } + + uart_irq_rx_enable(ctx->dev); +} + +static void mb_rx_disable(struct mb_rtu_context *ctx) +{ + uart_irq_rx_disable(ctx->dev); + if (ctx->re != NULL) { + gpio_pin_set(ctx->re->dev, ctx->re->pin, 0); + } +} + #ifdef CONFIG_MODBUS_RTU_ASCII_MODE /* The function calculates an 8-bit Longitudinal Redundancy Check. */ static uint8_t mb_ascii_get_lrc(uint8_t *src, size_t length) @@ -192,8 +249,8 @@ static void mb_tx_ascii_frame(struct mb_rtu_context *ctx) ctx->uart_buf_ptr = &ctx->uart_buf[0]; LOG_DBG("Start frame transmission"); - uart_irq_rx_disable(ctx->dev); - uart_irq_tx_enable(ctx->dev); + mb_rx_disable(ctx); + mb_tx_enable(ctx); } #else static int mb_rx_ascii_frame(struct mb_rtu_context *ctx) @@ -300,8 +357,8 @@ static void mb_tx_rtu_frame(struct mb_rtu_context *ctx) LOG_HEXDUMP_DBG(ctx->uart_buf, ctx->uart_buf_ctr, "uart_buf"); LOG_DBG("Start frame transmission"); - uart_irq_rx_disable(ctx->dev); - uart_irq_tx_enable(ctx->dev); + mb_rx_disable(ctx); + mb_tx_enable(ctx); } void mb_tx_frame(struct mb_rtu_context *ctx) @@ -372,8 +429,8 @@ static void mb_cb_handler_tx(struct mb_rtu_context *ctx) } else { /* Disable transmission */ ctx->uart_buf_ptr = &ctx->uart_buf[0]; - uart_irq_tx_disable(ctx->dev); - uart_irq_rx_enable(ctx->dev); + mb_tx_disable(ctx); + mb_rx_enable(ctx); } } @@ -408,7 +465,7 @@ static void mb_rx_handler(struct k_work *item) return; } - uart_irq_rx_disable(ctx->dev); + mb_rx_disable(ctx); if (IS_ENABLED(CONFIG_MODBUS_RTU_ASCII_MODE) && (ctx->ascii_mode == true)) { @@ -422,7 +479,7 @@ static void mb_rx_handler(struct k_work *item) } else if (IS_ENABLED(CONFIG_MODBUS_RTU_SERVER)) { if (mbs_rx_handler(ctx) == false) { /* Server does not send response, re-enable RX */ - uart_irq_rx_enable(ctx->dev); + mb_rx_enable(ctx); } } } @@ -487,7 +544,7 @@ static int mb_configure_uart(struct mb_rtu_context *ctx, } uart_irq_callback_user_data_set(ctx->dev, mb_uart_cb_handler, ctx); - uart_irq_rx_enable(ctx->dev); + mb_rx_enable(ctx); if (baudrate <= 38400) { ctx->rtu_timeout = (numof_bits * if_delay_max) / baudrate; @@ -519,6 +576,36 @@ struct mb_rtu_context *mb_get_context(const uint8_t iface) return ctx; } +static int mb_configure_gpio(struct mb_rtu_context *ctx) +{ + if (ctx->de != NULL) { + ctx->de->dev = device_get_binding(ctx->de->name); + if (ctx->de->dev == NULL) { + return -ENODEV; + } + + if (gpio_pin_configure(ctx->de->dev, ctx->de->pin, + GPIO_OUTPUT_INACTIVE | ctx->de->flags)) { + return -EIO; + } + } + + + if (ctx->re != NULL) { + ctx->re->dev = device_get_binding(ctx->re->name); + if (ctx->re->dev == NULL) { + return -ENODEV; + } + + if (gpio_pin_configure(ctx->re->dev, ctx->re->pin, + GPIO_OUTPUT_INACTIVE | ctx->re->flags)) { + return -EIO; + } + } + + return 0; +} + static struct mb_rtu_context *mb_cfg_iface(const uint8_t iface, const uint8_t node_addr, const uint32_t baud, @@ -565,6 +652,10 @@ static struct mb_rtu_context *mb_cfg_iface(const uint8_t iface, mbs_reset_statistics(ctx); } + if (mb_configure_gpio(ctx) != 0) { + return NULL; + } + if (mb_configure_uart(ctx, baud, parity) != 0) { LOG_ERR("Failed to configure UART"); return NULL; @@ -638,8 +729,8 @@ int mb_rtu_disable_iface(const uint8_t iface) ctx = &mb_ctx_tbl[iface]; - uart_irq_tx_disable(ctx->dev); - uart_irq_rx_disable(ctx->dev); + mb_tx_disable(ctx); + mb_rx_disable(ctx); k_timer_stop(&ctx->rtu_timer); ctx->rxwait_to = 0; diff --git a/subsys/modbus/mb_rtu_internal.h b/subsys/modbus/mb_rtu_internal.h index b3a77d3fd61..4d65c0e97dc 100644 --- a/subsys/modbus/mb_rtu_internal.h +++ b/subsys/modbus/mb_rtu_internal.h @@ -23,6 +23,7 @@ #define ZEPHYR_INCLUDE_MODBUS_RTU_INTERNAL_H_ #include +#include #include #ifdef CONFIG_MODBUS_RTU_FP_EXTENSIONS @@ -78,6 +79,13 @@ struct mb_rtu_frame { uint16_t crc; }; +struct mb_rtu_gpio_config { + const char *name; + const struct device *dev; + gpio_pin_t pin; + gpio_dt_flags_t flags; +}; + #define MB_RTU_STATE_CONFIGURED 0 struct mb_rtu_context { @@ -99,6 +107,10 @@ struct mb_rtu_context { atomic_t state; /* Pointer to current position in buffer */ uint8_t *uart_buf_ptr; + /* Pointer to driver enable (DE) pin config */ + struct mb_rtu_gpio_config *de; + /* Pointer to receiver enable (nRE) pin config */ + struct mb_rtu_gpio_config *re; /* Client's mutually exclusive access */ struct k_mutex iface_lock;