summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/mimxrt/boards/common.ld2
-rw-r--r--ports/mimxrt/machine_i2c.c13
-rw-r--r--ports/mimxrt/machine_i2c.h38
-rw-r--r--ports/mimxrt/machine_i2c_target.c168
-rw-r--r--ports/mimxrt/main.c1
-rw-r--r--ports/mimxrt/mpconfigport.h5
6 files changed, 217 insertions, 10 deletions
diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld
index 477ba38bc..dcbc0a423 100644
--- a/ports/mimxrt/boards/common.ld
+++ b/ports/mimxrt/boards/common.ld
@@ -98,7 +98,7 @@ SECTIONS
.text :
{
. = ALIGN(4);
- *(EXCLUDE_FILE(*fsl_flexspi.o *gc.o *vm.o *parse*.o *runtime*.o *map.o *mpirq.o ) .text*) /* .text* sections (code) */
+ *(EXCLUDE_FILE(*fsl_flexspi.o *gc.o *vm.o *runtime*.o *map.o *mpirq.o *machine_i2c_target.o *fsl_lpi2c.o) .text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
diff --git a/ports/mimxrt/machine_i2c.c b/ports/mimxrt/machine_i2c.c
index d170804f4..aa128e6ff 100644
--- a/ports/mimxrt/machine_i2c.c
+++ b/ports/mimxrt/machine_i2c.c
@@ -33,11 +33,7 @@
#include "fsl_iomuxc.h"
#include "fsl_lpi2c.h"
-
-#define DEFAULT_I2C_ID (0)
-#define DEFAULT_I2C_FREQ (400000)
-#define DEFAULT_I2C_DRIVE (6)
-#define DEFAULT_I2C_TIMEOUT (50000)
+#include "machine_i2c.h"
typedef struct _machine_i2c_obj_t {
mp_obj_base_t base;
@@ -57,12 +53,11 @@ typedef struct _iomux_table_t {
uint32_t configRegister;
} iomux_table_t;
-static const uint8_t i2c_index_table[] = MICROPY_HW_I2C_INDEX;
-static LPI2C_Type *i2c_base_ptr_table[] = LPI2C_BASE_PTRS;
+const uint8_t i2c_index_table[] = MICROPY_HW_I2C_INDEX;
+LPI2C_Type *i2c_base_ptr_table[] = LPI2C_BASE_PTRS;
+const uint8_t micropy_hw_i2c_num = MICROPY_HW_I2C_NUM;
static const iomux_table_t iomux_table[] = { IOMUX_TABLE_I2C };
-#define MICROPY_HW_I2C_NUM ARRAY_SIZE(i2c_index_table)
-
#define SCL (iomux_table[index])
#define SDA (iomux_table[index + 1])
diff --git a/ports/mimxrt/machine_i2c.h b/ports/mimxrt/machine_i2c.h
new file mode 100644
index 000000000..c6d561ca5
--- /dev/null
+++ b/ports/mimxrt/machine_i2c.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Damien P. George
+ * Copyright (c) 2025 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define DEFAULT_I2C_ID (0)
+#define DEFAULT_I2C_FREQ (400000)
+#define DEFAULT_I2C_DRIVE (6)
+#define DEFAULT_I2C_TIMEOUT (50000)
+#define DEFAULT_I2C_FILTER_NS (200)
+#define MICROPY_HW_I2C_NUM ARRAY_SIZE(i2c_index_table)
+
+extern const uint8_t i2c_index_table[];
+extern LPI2C_Type *i2c_base_ptr_table[];
+extern bool lpi2c_set_iomux(int8_t hw_i2c, uint8_t drive);
+extern const uint8_t micropy_hw_i2c_num;
diff --git a/ports/mimxrt/machine_i2c_target.c b/ports/mimxrt/machine_i2c_target.c
new file mode 100644
index 000000000..aa408071f
--- /dev/null
+++ b/ports/mimxrt/machine_i2c_target.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Damien P. George
+ * Copyright (c) 2025 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file is never compiled standalone, it's included directly from
+// extmod/machine_i2c_target.c via MICROPY_PY_MACHINE_I2C_TARGET_INCLUDEFILE.
+
+#include "fsl_lpi2c.h"
+#include "machine_i2c.h"
+#include CLOCK_CONFIG_H
+
+typedef struct _machine_i2c_target_obj_t {
+ mp_obj_base_t base;
+ LPI2C_Type *i2c_inst;
+ uint8_t i2c_id;
+ uint8_t addr;
+ lpi2c_slave_config_t slave_config;
+ lpi2c_slave_handle_t handle;
+} machine_i2c_target_obj_t;
+
+static void lpi2c_slave_callback(LPI2C_Type *base, lpi2c_slave_transfer_t *xfer, void *param) {
+ machine_i2c_target_obj_t *self = (machine_i2c_target_obj_t *)param;
+ machine_i2c_target_data_t *data = &machine_i2c_target_data[self->i2c_id];
+
+ switch (xfer->event) {
+ case kLPI2C_SlaveAddressMatchEvent:
+ // Controller addressed us.
+ machine_i2c_target_data_addr_match(data, xfer->receivedAddress & 1);
+ break;
+ case kLPI2C_SlaveReceiveEvent:
+ // Data from controller is available for reading.
+ machine_i2c_target_data_write_request(self, data);
+ break;
+ case kLPI2C_SlaveTransmitEvent:
+ // Controller is requesting data.
+ machine_i2c_target_data_read_request(self, data);
+ break;
+ case kLPI2C_SlaveCompletionEvent:
+ // Transfer done.
+ machine_i2c_target_data_stop(data);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************/
+// I2CTarget port implementation
+
+static inline size_t mp_machine_i2c_target_get_index(machine_i2c_target_obj_t *self) {
+ return self->i2c_id;
+}
+
+static inline void mp_machine_i2c_target_event_callback(machine_i2c_target_irq_obj_t *irq) {
+ mp_irq_handler(&irq->base);
+}
+
+static size_t mp_machine_i2c_target_read_bytes(machine_i2c_target_obj_t *self, size_t len, uint8_t *buf) {
+ // LPI2C_Type *i2c_inst = self->i2c_inst;
+ // mp_int_t i = 0;
+ // mp_int_t val = 0;
+ // while (i < len && !((val = i2c_inst->SRDR) & LPI2C_SRDR_RXEMPTY_MASK)) {
+ // buf[i++] = (uint8_t)(val & 0xff);
+ // }
+ // return i;
+ // Simple and fast version for len == 1
+ buf[0] = (uint8_t)(self->i2c_inst->SRDR);
+ return 1;
+}
+
+static size_t mp_machine_i2c_target_write_bytes(machine_i2c_target_obj_t *self, size_t len, const uint8_t *buf) {
+ self->i2c_inst->STDR = buf[0];
+ return 1;
+}
+
+static inline void mp_machine_i2c_target_irq_config(machine_i2c_target_obj_t *self, unsigned int trigger) {
+ (void)self;
+ (void)trigger;
+}
+
+static mp_obj_t mp_machine_i2c_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_addr, ARG_addrsize, ARG_mem, ARG_mem_addrsize, ARG_drive };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT, {.u_int = DEFAULT_I2C_ID} },
+ { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 7} },
+ { MP_QSTR_mem, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+ { MP_QSTR_mem_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_DRIVE} },
+ };
+
+ // Parse arguments.
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Get I2C bus.
+ int i2c_id = args[ARG_id].u_int;
+ if (i2c_id < 0 || i2c_id >= micropy_hw_i2c_num || i2c_index_table[i2c_id] == 0) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
+ }
+ int i2c_hw_id = i2c_index_table[i2c_id]; // the hw i2c number 1..n
+
+ // Get I2C Object.
+ machine_i2c_target_obj_t *self = mp_obj_malloc_with_finaliser(machine_i2c_target_obj_t, &machine_i2c_target_type);
+ self->i2c_id = i2c_id;
+ self->i2c_inst = i2c_base_ptr_table[i2c_hw_id];
+ uint8_t drive = args[ARG_drive].u_int;
+ if (drive < 1 || drive > 7) {
+ drive = DEFAULT_I2C_DRIVE;
+ }
+ // Set the target address.
+ self->addr = args[ARG_addr].u_int;
+ // Initialise data.
+ MP_STATE_PORT(machine_i2c_target_mem_obj)[i2c_id] = args[ARG_mem].u_obj;
+ machine_i2c_target_data_t *data = &machine_i2c_target_data[self->i2c_id];
+ machine_i2c_target_data_init(data, args[ARG_mem].u_obj, args[ARG_mem_addrsize].u_int);
+
+ // Initialise the GPIO pins
+ lpi2c_set_iomux(i2c_hw_id, drive);
+ // Initialise the I2C peripheral
+ LPI2C_SlaveGetDefaultConfig(&self->slave_config);
+ self->slave_config.address0 = self->addr;
+ self->slave_config.sdaGlitchFilterWidth_ns = DEFAULT_I2C_FILTER_NS;
+ self->slave_config.sclGlitchFilterWidth_ns = DEFAULT_I2C_FILTER_NS;
+ LPI2C_SlaveInit(self->i2c_inst, &self->slave_config, BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT);
+ // Create the LPI2C handle for the non-blocking transfer
+ LPI2C_SlaveTransferCreateHandle(self->i2c_inst, &self->handle, lpi2c_slave_callback, self);
+ // Start accepting I2C transfers on the LPI2C slave peripheral
+ status_t reVal = LPI2C_SlaveTransferNonBlocking(self->i2c_inst, &self->handle,
+ kLPI2C_SlaveAddressMatchEvent | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent | kLPI2C_SlaveCompletionEvent);
+ if (reVal != kStatus_Success) {
+ mp_raise_ValueError(MP_ERROR_TEXT("cannot start I2C"));
+ }
+ return MP_OBJ_FROM_PTR(self);
+}
+
+static void mp_machine_i2c_target_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "I2CTarget(%u, addr=%u)", self->i2c_id, self->addr);
+}
+
+// Stop the Slave transfer and free the memory objects.
+static void mp_machine_i2c_target_deinit(machine_i2c_target_obj_t *self) {
+ LPI2C_SlaveDeinit(self->i2c_inst);
+}
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index 6b9d4fa17..7166171f1 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -55,6 +55,7 @@
#endif
#include "systick.h"
+#include "extmod/modmachine.h"
#include "extmod/modnetwork.h"
#include "extmod/vfs.h"
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index e1c605f45..8ceb3b418 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -92,6 +92,11 @@ uint32_t trng_random_u32(void);
#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/mimxrt/machine_pwm.c"
#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_I2C_TARGET (1)
+#define MICROPY_PY_MACHINE_I2C_TARGET_INCLUDEFILE "ports/mimxrt/machine_i2c_target.c"
+#define MICROPY_PY_MACHINE_I2C_TARGET_MAX (FSL_FEATURE_SOC_LPI2C_COUNT)
+#define MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ (1)
+#define MICROPY_PY_MACHINE_I2C_TARGET_FINALISER (1)
#ifndef MICROPY_PY_MACHINE_I2S
#define MICROPY_PY_MACHINE_I2S (0)
#endif