From 56b168b0868450ca3edf021290dd1dc013cc7609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Tue, 13 Jan 2026 14:02:57 +0100 Subject: [PATCH] zephyr/machine_i2c: Rework I2C driver to make continuous transactions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using `mp_machine_i2c_transfer_adaptor` and instead implement support for `MP_MACHINE_I2C_FLAG_WRITE1`. That allows combined write-read transactions like `I2C.readfrom_mem()` to work properly with a RESTART, instead of being split into a separate write-with-STOP followed by a read-with-STOP (many I2C controllers in zephyr don't support incomplete transactions). Signed-off-by: Fin Maaß --- ports/zephyr/machine_i2c.c | 83 +++++++++++++++++++++++++++---------- ports/zephyr/mpconfigport.h | 1 + 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/ports/zephyr/machine_i2c.c b/ports/zephyr/machine_i2c.c index 24281b661d..30eff870f4 100644 --- a/ports/zephyr/machine_i2c.c +++ b/ports/zephyr/machine_i2c.c @@ -5,6 +5,7 @@ * * Copyright (c) 2013, 2014, 2015 Damien P. George * Copyright (c) 2019, NXP + * Copyright (c) 2026 Fin Maaß * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,7 +45,6 @@ typedef struct _machine_hard_i2c_obj_t { mp_obj_base_t base; const struct device *dev; - bool restart; } machine_hard_i2c_obj_t; static void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -82,44 +82,85 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz machine_hard_i2c_obj_t *self = mp_obj_malloc(machine_hard_i2c_obj_t, &machine_i2c_type); self->dev = dev; - self->restart = false; return MP_OBJ_FROM_PTR(self); } -static int machine_hard_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { +static int machine_hard_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) { machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; - struct i2c_msg msg; + struct i2c_msg msg[2] = {0}; int ret; + size_t len; + size_t i; + uint8_t start_idx = 0; - msg.buf = (uint8_t *)buf; - msg.len = len; - msg.flags = 0; + if (flags & MP_MACHINE_I2C_FLAG_WRITE1) { + msg[0].buf = bufs[0].buf; + msg[0].len = bufs[0].len; + msg[0].flags = I2C_MSG_WRITE; + msg[1].flags = I2C_MSG_RESTART; + start_idx = 1; + n--; + bufs++; + } + + if (n == 0) { + return -MP_EINVAL; + } + + if (!(flags & MP_MACHINE_I2C_FLAG_STOP)) { + return -MP_EINVAL; + } if (flags & MP_MACHINE_I2C_FLAG_READ) { - msg.flags |= I2C_MSG_READ; + msg[start_idx].flags |= I2C_MSG_READ | I2C_MSG_STOP; } else { - msg.flags |= I2C_MSG_WRITE; + msg[start_idx].flags |= I2C_MSG_WRITE | I2C_MSG_STOP; } - if (self->restart) { - msg.flags |= I2C_MSG_RESTART; - } - - if (flags & MP_MACHINE_I2C_FLAG_STOP) { - msg.flags |= I2C_MSG_STOP; - self->restart = false; + if (n == 1) { + // Use given single buffer + msg[start_idx].buf = bufs[0].buf; + msg[start_idx].len = bufs[0].len; } else { - self->restart = true; + // Combine buffers into a single one + msg[start_idx].len = 0; + for (i = 0; i < n; ++i) { + msg[start_idx].len += bufs[i].len; + } + msg[start_idx].buf = m_new(uint8_t, msg[start_idx].len); + if (!(flags & MP_MACHINE_I2C_FLAG_READ)) { + len = 0; + for (i = 0; i < n; ++i) { + memcpy(&msg[start_idx].buf[len], bufs[i].buf, bufs[i].len); + len += bufs[i].len; + } + } } - ret = i2c_transfer(self->dev, &msg, 1, addr); - return (ret < 0) ? -MP_EIO : len; + ret = i2c_transfer(self->dev, msg, start_idx + 1, addr); + if (ret < 0) { + return -MP_EIO; + } + + if (n > 1) { + if (flags & MP_MACHINE_I2C_FLAG_READ) { + // Copy data from single buffer to individual ones + len = 0; + for (i = 0; i < n; ++i) { + memcpy(bufs[i].buf, &msg[start_idx].buf[len], bufs[i].len); + len += bufs[i].len; + } + } + m_del(uint8_t, msg[start_idx].buf, msg[start_idx].len); + } + + return msg[0].len + msg[1].len; } static const mp_machine_i2c_p_t machine_hard_i2c_p = { - .transfer = mp_machine_i2c_transfer_adaptor, - .transfer_single = machine_hard_i2c_transfer_single, + .transfer_supports_write1 = true, + .transfer = machine_hard_i2c_transfer, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index ceaa6df43c..695e456784 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -75,6 +75,7 @@ #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_INCLUDEFILE "ports/zephyr/modmachine.c" #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1 (1) #ifdef CONFIG_I2C_TARGET #define MICROPY_PY_MACHINE_I2C_TARGET (1) #define MICROPY_PY_MACHINE_I2C_TARGET_INCLUDEFILE "ports/zephyr/machine_i2c_target.c"