From 5478cb308ed3e44727233381049168d966e76c74 Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Thu, 4 Dec 2025 15:41:21 +0100 Subject: [PATCH 1/7] psoc-edge/machine_i2c: I2C master basic function and clean up. Signed-off-by: zhanglinjing --- ports/psoc-edge/machine_i2c.c | 318 +++++++++++++++++++++++++++------- ports/psoc-edge/machine_i2c.h | 10 +- 2 files changed, 266 insertions(+), 62 deletions(-) diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index 0cf4634fad814..2d84b91204b1b 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -33,10 +33,15 @@ #include "extmod/modmachine.h" #include "py/runtime.h" #include "py/mphal.h" +#include "py/mperrno.h" // MTB includes #include "cybsp.h" +#include "cy_scb_i2c.h" +#include "cy_sysint.h" +#include "cy_sysclk.h" +#include "mtb_hal_i2c.h" // port-specific includes @@ -51,66 +56,257 @@ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(msg), ret); \ } -typedef struct _machine_i2c_obj_t { +typedef struct _machine_hw_i2c_obj_t { mp_obj_base_t base; int id; // This parameter is unused and added for compliance with reference API. - mtb_hal_i2c_t i2c_obj; uint32_t scl_pin; uint32_t sda_pin; - mtb_hal_i2c_cfg_t cfg; - mp_obj_t callback; -} machine_i2c_obj_t; - - -// const cy_stc_scb_i2c_config_t CYBSP_I2C_CONTROLLER_config = -// { -// .i2cMode = CY_SCB_I2C_MASTER, -// .useRxFifo = true, -// .useTxFifo = true, -// .slaveAddress = 0U, -// .slaveAddressMask = 0U, -// .acceptAddrInFifo = false, -// .ackGeneralAddr = false, -// .enableWakeFromSleep = false, -// .enableDigitalFilter = false, -// .lowPhaseDutyCycle = 16, -// .highPhaseDutyCycle = 9, -// }; - -machine_i2c_obj_t *i2c_obj[MAX_I2C] = { NULL }; - -static inline machine_i2c_obj_t *i2c_obj_alloc(bool is_slave) { + uint32_t freq; // Configured frequency + mtb_hal_i2c_t hal_obj; // HAL I2C object for setup +} machine_hw_i2c_obj_t; + +// Static configuration and context for each I2C instance +static cy_stc_scb_i2c_config_t machine_hw_i2c_cfg[MAX_I2C]; +static cy_stc_scb_i2c_context_t machine_hw_i2c_ctx[MAX_I2C]; + +machine_hw_i2c_obj_t *machine_hw_i2c_obj[MAX_I2C] = { NULL }; + +// I2C interrupt service routine +// Note: Using master-specific interrupt function to reduce flash consumption +static void machine_i2c_isr(void) { + // Find which I2C instance triggered the interrupt + for (uint8_t i = 0; i < MAX_I2C; i++) { + if (machine_hw_i2c_obj[i] != NULL) { + // Call I2C master interrupt handler (more efficient than generic Cy_SCB_I2C_Interrupt) + Cy_SCB_I2C_MasterInterrupt(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i]); + } + } +} + +static inline machine_hw_i2c_obj_t *machine_hw_i2c_obj_alloc(void) { for (uint8_t i = 0; i < MAX_I2C; i++) { - if (i2c_obj[i] == NULL) { - const mp_obj_type_t *obj_type; - obj_type = &machine_i2c_type; - i2c_obj[i] = mp_obj_malloc(machine_i2c_obj_t, obj_type); - return i2c_obj[i]; + if (machine_hw_i2c_obj[i] == NULL) { + machine_hw_i2c_obj[i] = mp_obj_malloc(machine_hw_i2c_obj_t, &machine_i2c_type); + return machine_hw_i2c_obj[i]; } } + // Debug: print status of all slots + mp_printf(&mp_plat_print, "I2C alloc failed - all slots occupied:\n"); + for (uint8_t i = 0; i < MAX_I2C; i++) { + mp_printf(&mp_plat_print, " Slot %u: %p\n", i, machine_hw_i2c_obj[i]); + } + return NULL; } -static inline void i2c_obj_free(machine_i2c_obj_t *i2c_obj_ptr) { +static inline void machine_hw_i2c_obj_free(machine_hw_i2c_obj_t *i2c_obj_ptr) { for (uint8_t i = 0; i < MAX_I2C; i++) { - if (i2c_obj[i] == i2c_obj_ptr) { - i2c_obj[i] = NULL; + if (machine_hw_i2c_obj[i] == i2c_obj_ptr) { + machine_hw_i2c_obj[i] = NULL; } } } -static void i2c_init(machine_i2c_obj_t *machine_i2c_obj, uint32_t freq_hz) { +static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { + cy_rslt_t result; + + // Get I2C instance ID + uint8_t i2c_id = 0; + for (uint8_t i = 0; i < MAX_I2C; i++) { + if (machine_hw_i2c_obj[i] == self) { + i2c_id = i; + break; + } + } + + // 1. Populate I2C master configuration structure (following PDL example) + const cy_stc_scb_i2c_config_t i2cConfig = { + .i2cMode = CY_SCB_I2C_MASTER, + .useRxFifo = false, + .useTxFifo = true, + .slaveAddress = 0U, + .slaveAddressMask = 0U, + .acceptAddrInFifo = false, + .ackGeneralAddr = false, + .enableWakeFromSleep = false, + .enableDigitalFilter = false, + .lowPhaseDutyCycle = 8U, + .highPhaseDutyCycle = 8U, + }; + + // Save to static array + machine_hw_i2c_cfg[i2c_id] = i2cConfig; + + // 2. Configure pins for I2C operation + Cy_GPIO_SetHSIOM(GPIO_PRT17, self->scl_pin, P17_0_SCB5_I2C_SCL); + Cy_GPIO_SetHSIOM(GPIO_PRT17, self->sda_pin, P17_1_SCB5_I2C_SDA); + Cy_GPIO_SetDrivemode(GPIO_PRT17, self->scl_pin, CY_GPIO_DM_OD_DRIVESLOW); + Cy_GPIO_SetDrivemode(GPIO_PRT17, self->sda_pin, CY_GPIO_DM_OD_DRIVESLOW); + + // 3. Initialize I2C with PDL (configure I2C to operate) + result = Cy_SCB_I2C_Init(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_cfg[i2c_id], &machine_hw_i2c_ctx[i2c_id]); + if (result != CY_RSLT_SUCCESS) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C init failed: 0x%lx"), result); + } + + // 4. Configure clock divider for I2C + // For desired data rate, clk_scb frequency must be in valid range (see TRM I2C Oversampling section) + // For 100kHz: clk_scb range is 1.55 - 3.2 MHz + // - clk_peri = 50 MHz, divider = 32 → clk_scb = 1.563 MHz ✓ + // For 400kHz: clk_scb range is 7.82 - 15.38 MHz + // - clk_peri = 50 MHz, divider = 4 → clk_scb = 12.5 MHz ✓ + // Note: Cy_SysClk_PeriphSetDivider takes (divider - 1), so divider=4 → value=3 + uint32_t divider = (freq_hz <= 100000) ? 31U : 3U; + Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 0U, divider); + Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 0U); + + // 5. Configure master data rate + uint32_t clk_scb_freq = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 0U); + uint32_t actual_rate = Cy_SCB_I2C_SetDataRate(MICROPY_HW_I2C0_SCB, freq_hz, clk_scb_freq); + + if ((actual_rate > freq_hz) || (actual_rate == 0U)) { + mp_raise_msg_varg(&mp_type_ValueError, + MP_ERROR_TEXT("Cannot reach desired I2C data rate %u Hz (actual: %u Hz)"), + freq_hz, actual_rate); + } + + // 6. Configure interrupt (mandatory for I2C operation) + // Populate interrupt configuration structure + #define I2C_INTR_PRIORITY (7UL) + const cy_stc_sysint_t i2cIntrConfig = { + .intrSrc = scb_5_interrupt_IRQn, + .intrPriority = I2C_INTR_PRIORITY, + }; + + // Hook interrupt service routine and enable interrupt in NVIC + result = Cy_SysInt_Init(&i2cIntrConfig, &machine_i2c_isr); + if (result != CY_RSLT_SUCCESS) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C interrupt init failed: 0x%lx"), result); + } + NVIC_EnableIRQ(scb_5_interrupt_IRQn); + + // 7. Enable I2C operation + Cy_SCB_I2C_Enable(MICROPY_HW_I2C0_SCB); + + mp_printf(&mp_plat_print, "I2C initialized: requested=%u Hz, actual=%u Hz, clk_scb=%u Hz\n", + freq_hz, actual_rate, clk_scb_freq); + + // Store requested frequency + self->freq = freq_hz; } -static void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "I2C(freq=%u, scl=%u, sda=%u, addr=%u)", self->cfg.frequency_hz, self->scl_pin, self->sda_pin, self->cfg.address); + +static int machine_hw_i2c_deinit(mp_obj_base_t *self_in) { + machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Get I2C instance ID + uint8_t i2c_id = 0; + for (uint8_t i = 0; i < MAX_I2C; i++) { + if (machine_hw_i2c_obj[i] == self) { + i2c_id = i; + break; + } + } + + // Disable I2C operation + Cy_SCB_I2C_Disable(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]); + + // Disable interrupt in NVIC + NVIC_DisableIRQ(scb_5_interrupt_IRQn); + + // Disable clock divider + Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_8_BIT, 0U); + + // Free the object slot + machine_hw_i2c_obj_free(self); + + return 0; // Success +} + +static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { + machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + cy_rslt_t result; + + // Get I2C instance ID + uint8_t i2c_id = 0; + for (uint8_t i = 0; i < MAX_I2C; i++) { + if (machine_hw_i2c_obj[i] == self) { + i2c_id = i; + break; + } + } + + mp_printf(&mp_plat_print, "I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", + addr, len, flags, (flags & MP_MACHINE_I2C_FLAG_READ) ? "READ" : "WRITE"); + + // Configure transfer structure + cy_stc_scb_i2c_master_xfer_config_t transfer; + transfer.slaveAddress = addr; + transfer.buffer = buf; + transfer.bufferSize = len; + // Generate Stop condition if MP_MACHINE_I2C_FLAG_STOP is set + transfer.xferPending = !(flags & MP_MACHINE_I2C_FLAG_STOP); + + // Initiate read or write transaction (non-blocking) + if (flags & MP_MACHINE_I2C_FLAG_READ) { + // Initiate read transaction + result = Cy_SCB_I2C_MasterRead(MICROPY_HW_I2C0_SCB, &transfer, &machine_hw_i2c_ctx[i2c_id]); + } else { + // Initiate write transaction + result = Cy_SCB_I2C_MasterWrite(MICROPY_HW_I2C0_SCB, &transfer, &machine_hw_i2c_ctx[i2c_id]); + } + + if (result != CY_RSLT_SUCCESS) { + mp_printf(&mp_plat_print, "I2C Transfer start failed: 0x%lx\n", result); + return -MP_EIO; // I/O error + } + + mp_printf(&mp_plat_print, "I2C Transfer started, waiting for completion...\n"); + + // Wait for transaction completion + // The interrupt handler (Cy_SCB_I2C_MasterInterrupt) processes the transaction + uint32_t timeout = 100000; // Timeout counter + while (0UL != (CY_SCB_I2C_MASTER_BUSY & Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]))) { + // Yield to allow other tasks/interrupts to run + MICROPY_EVENT_POLL_HOOK + if (--timeout == 0) { + mp_printf(&mp_plat_print, "I2C Transfer timeout!\n"); + return -MP_ETIMEDOUT; + } + } + + // Check if there were any errors during the transfer + uint32_t master_status = Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]); + + mp_printf(&mp_plat_print, "I2C Transfer complete, status=0x%08lX\n", master_status); + + if (master_status & CY_SCB_I2C_MASTER_ERR) { + // Error occurred during transfer + mp_printf(&mp_plat_print, "I2C Transfer error detected in status\n"); + return -MP_EIO; // I/O error + } + + // Return number of bytes transferred + return len; } -mp_obj_t machine_i2c_master_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { +/******************************************************************************/ +// MicroPython bindings for machine API + +static void machine_hw_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Print I2C configuration + mp_printf(print, "I2C(scl=%u, sda=%u, freq=%u)", + self->scl_pin, + self->sda_pin, + self->freq); +} + +mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 0, 4, true); enum { ARG_id, ARG_freq, ARG_scl, ARG_sda }; @@ -118,17 +314,17 @@ mp_obj_t machine_i2c_master_make_new(const mp_obj_type_t *type, size_t n_args, s static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = -1}}, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} }, - { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} } + { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} } }; // Parse args. 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); - machine_i2c_obj_t *self = i2c_obj_alloc(false); + machine_hw_i2c_obj_t *self = machine_hw_i2c_obj_alloc(); if (self == NULL) { - return mp_const_none; + mp_raise_ValueError(MP_ERROR_TEXT("Maximum number of I2C instances reached")); } // set id if provided @@ -137,33 +333,37 @@ mp_obj_t machine_i2c_master_make_new(const mp_obj_type_t *type, size_t n_args, s mp_printf(&mp_plat_print, "machine.I2C: ID parameter is ignored in this port.\n"); } - // initialise I2C at cyhal level - i2c_init(self, args[ARG_freq].u_int); - - return MP_OBJ_FROM_PTR(self); -} + // Parse and validate pin arguments, use defaults from machine_i2c.h if not provided + if (args[ARG_scl].u_obj != MP_ROM_NONE) { + self->scl_pin = mp_obj_get_int(args[ARG_scl].u_obj); + } else { + self->scl_pin = MICROPY_HW_I2C0_SCL; // Default from machine_i2c.h + } + if (args[ARG_sda].u_obj != MP_ROM_NONE) { + self->sda_pin = mp_obj_get_int(args[ARG_sda].u_obj); + } else { + self->sda_pin = MICROPY_HW_I2C0_SDA; // Default from machine_i2c.h + } -static void machine_i2c_deinit(mp_obj_base_t *self_in) { - machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - i2c_obj_free(self); -} + // initialise I2C at hardware level + machine_hw_i2c_init(self, args[ARG_freq].u_int); -static int machine_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { - return 0; + return MP_OBJ_FROM_PTR(self); } -static const mp_machine_i2c_p_t machine_i2c_p = { - .transfer_single = machine_i2c_transfer, - // .transfer = mp_machine_i2c_transfer_adaptor +static const mp_machine_i2c_p_t machine_hw_i2c_p = { + .stop = machine_hw_i2c_deinit, // Map stop() to deinit functionality + .transfer = mp_machine_i2c_transfer_adaptor, + .transfer_single = machine_hw_i2c_transfer, }; MP_DEFINE_CONST_OBJ_TYPE( machine_i2c_type, MP_QSTR_I2C, MP_TYPE_FLAG_NONE, - make_new, machine_i2c_master_make_new, - print, machine_i2c_print, - protocol, &machine_i2c_p, + make_new, machine_hw_i2c_make_new, + print, machine_hw_i2c_print, + protocol, &machine_hw_i2c_p, locals_dict, &mp_machine_i2c_locals_dict ); diff --git a/ports/psoc-edge/machine_i2c.h b/ports/psoc-edge/machine_i2c.h index 7efe1545d43b3..692bd34691ef8 100644 --- a/ports/psoc-edge/machine_i2c.h +++ b/ports/psoc-edge/machine_i2c.h @@ -27,11 +27,15 @@ #ifndef MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H #define MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H -// Configure default I2C0 pins. +// Configure default I2C0 pins and SCB peripheral #ifndef MICROPY_HW_I2C0_SCL -#define MICROPY_HW_I2C0_SCL (GPIO_NUM_9) -#define MICROPY_HW_I2C0_SDA (GPIO_NUM_8) +#define MICROPY_HW_I2C0_SCB (SCB5) +#define MICROPY_HW_I2C0_SCL (P17_0_NUM) +#define MICROPY_HW_I2C0_SDA (P17_1_NUM) #define MAX_I2C 1 #endif +// Declare the I2C type for external use +extern const mp_obj_type_t machine_i2c_type; + #endif // MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H From e83135f6bb4f296dc9a41c18bfbee735bd368d48 Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Fri, 5 Dec 2025 17:10:14 +0100 Subject: [PATCH 2/7] psoc-edge/machine_i2c: Fix 400kHz issue. Signed-off-by: zhanglinjing --- ports/psoc-edge/machine_i2c.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index 2d84b91204b1b..31f82056c9f28 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -152,20 +152,25 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C init failed: 0x%lx"), result); } - // 4. Configure clock divider for I2C + // 4. Configure clock divider for I2C (balanced performance and power) // For desired data rate, clk_scb frequency must be in valid range (see TRM I2C Oversampling section) - // For 100kHz: clk_scb range is 1.55 - 3.2 MHz - // - clk_peri = 50 MHz, divider = 32 → clk_scb = 1.563 MHz ✓ - // For 400kHz: clk_scb range is 7.82 - 15.38 MHz - // - clk_peri = 50 MHz, divider = 4 → clk_scb = 12.5 MHz ✓ - // Note: Cy_SysClk_PeriphSetDivider takes (divider - 1), so divider=4 → value=3 - uint32_t divider = (freq_hz <= 100000) ? 31U : 3U; - Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 0U, divider); - Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 0U); + // For 100kHz: clk_scb range is 1.55 - 3.2 MHz (architecture reference manual 002-38331 Rev. P685 table 355) + // - clk_peri = 100 MHz, divider = 42 → clk_scb = 2.38 MHz ✓ (mid-range) + // For 400kHz: clk_scb range is 7.82 - 10 MHz + // - clk_peri = 100 MHz, divider = 11 → clk_scb = 9.09 MHz ✓ (within range) + // Note: Cy_SysClk_PeriphSetDivider takes (divider - 1), so divider=11 → value=10 + /* Connect assigned divider to be a clock source for I2C */ + Cy_SysClk_PeriphAssignDivider(PCLK_SCB5_CLOCK_SCB_EN, CY_SYSCLK_DIV_8_BIT, 2U); + uint32_t divider = (freq_hz <= 100000) ? 41U : 10U; + Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 2U, divider); + Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 2U); // 5. Configure master data rate - uint32_t clk_scb_freq = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 0U); + uint32_t clk_scb_freq = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 2U); + mp_printf(&mp_plat_print, "DEBUG: clk_scb_freq=%u Hz\n", clk_scb_freq); + uint32_t actual_rate = Cy_SCB_I2C_SetDataRate(MICROPY_HW_I2C0_SCB, freq_hz, clk_scb_freq); + mp_printf(&mp_plat_print, "DEBUG: actual_rate=%u Hz (requested=%u Hz)\n", actual_rate, freq_hz); if ((actual_rate > freq_hz) || (actual_rate == 0U)) { mp_raise_msg_varg(&mp_type_ValueError, From 480e37a9ee8d05f92364f6121796899a6e19842d Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Wed, 10 Dec 2025 11:10:25 +0100 Subject: [PATCH 3/7] psoc-edge/machine_i2c: Remove HAL and add PDL config in obj. Signed-off-by: zhanglinjing --- ports/psoc-edge/machine_i2c.c | 54 +++++++---------------------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index 31f82056c9f28..d5266ac6b794e 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -41,7 +41,6 @@ #include "cy_scb_i2c.h" #include "cy_sysint.h" #include "cy_sysclk.h" -#include "mtb_hal_i2c.h" // port-specific includes @@ -62,13 +61,10 @@ typedef struct _machine_hw_i2c_obj_t { uint32_t scl_pin; uint32_t sda_pin; uint32_t freq; // Configured frequency - mtb_hal_i2c_t hal_obj; // HAL I2C object for setup + cy_stc_scb_i2c_config_t cfg; // PDL I2C configuration + cy_stc_scb_i2c_context_t ctx; // PDL I2C runtime context } machine_hw_i2c_obj_t; -// Static configuration and context for each I2C instance -static cy_stc_scb_i2c_config_t machine_hw_i2c_cfg[MAX_I2C]; -static cy_stc_scb_i2c_context_t machine_hw_i2c_ctx[MAX_I2C]; - machine_hw_i2c_obj_t *machine_hw_i2c_obj[MAX_I2C] = { NULL }; // I2C interrupt service routine @@ -78,7 +74,7 @@ static void machine_i2c_isr(void) { for (uint8_t i = 0; i < MAX_I2C; i++) { if (machine_hw_i2c_obj[i] != NULL) { // Call I2C master interrupt handler (more efficient than generic Cy_SCB_I2C_Interrupt) - Cy_SCB_I2C_MasterInterrupt(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i]); + Cy_SCB_I2C_MasterInterrupt(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_obj[i]->ctx); } } } @@ -113,17 +109,8 @@ static inline void machine_hw_i2c_obj_free(machine_hw_i2c_obj_t *i2c_obj_ptr) { static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { cy_rslt_t result; - // Get I2C instance ID - uint8_t i2c_id = 0; - for (uint8_t i = 0; i < MAX_I2C; i++) { - if (machine_hw_i2c_obj[i] == self) { - i2c_id = i; - break; - } - } - // 1. Populate I2C master configuration structure (following PDL example) - const cy_stc_scb_i2c_config_t i2cConfig = { + self->cfg = (cy_stc_scb_i2c_config_t) { .i2cMode = CY_SCB_I2C_MASTER, .useRxFifo = false, .useTxFifo = true, @@ -137,9 +124,6 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { .highPhaseDutyCycle = 8U, }; - // Save to static array - machine_hw_i2c_cfg[i2c_id] = i2cConfig; - // 2. Configure pins for I2C operation Cy_GPIO_SetHSIOM(GPIO_PRT17, self->scl_pin, P17_0_SCB5_I2C_SCL); Cy_GPIO_SetHSIOM(GPIO_PRT17, self->sda_pin, P17_1_SCB5_I2C_SDA); @@ -147,7 +131,7 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { Cy_GPIO_SetDrivemode(GPIO_PRT17, self->sda_pin, CY_GPIO_DM_OD_DRIVESLOW); // 3. Initialize I2C with PDL (configure I2C to operate) - result = Cy_SCB_I2C_Init(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_cfg[i2c_id], &machine_hw_i2c_ctx[i2c_id]); + result = Cy_SCB_I2C_Init(MICROPY_HW_I2C0_SCB, &self->cfg, &self->ctx); if (result != CY_RSLT_SUCCESS) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C init failed: 0x%lx"), result); } @@ -207,17 +191,8 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { static int machine_hw_i2c_deinit(mp_obj_base_t *self_in) { machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Get I2C instance ID - uint8_t i2c_id = 0; - for (uint8_t i = 0; i < MAX_I2C; i++) { - if (machine_hw_i2c_obj[i] == self) { - i2c_id = i; - break; - } - } - // Disable I2C operation - Cy_SCB_I2C_Disable(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]); + Cy_SCB_I2C_Disable(MICROPY_HW_I2C0_SCB, &self->ctx); // Disable interrupt in NVIC NVIC_DisableIRQ(scb_5_interrupt_IRQn); @@ -235,15 +210,6 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); cy_rslt_t result; - // Get I2C instance ID - uint8_t i2c_id = 0; - for (uint8_t i = 0; i < MAX_I2C; i++) { - if (machine_hw_i2c_obj[i] == self) { - i2c_id = i; - break; - } - } - mp_printf(&mp_plat_print, "I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", addr, len, flags, (flags & MP_MACHINE_I2C_FLAG_READ) ? "READ" : "WRITE"); @@ -258,10 +224,10 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Initiate read or write transaction (non-blocking) if (flags & MP_MACHINE_I2C_FLAG_READ) { // Initiate read transaction - result = Cy_SCB_I2C_MasterRead(MICROPY_HW_I2C0_SCB, &transfer, &machine_hw_i2c_ctx[i2c_id]); + result = Cy_SCB_I2C_MasterRead(MICROPY_HW_I2C0_SCB, &transfer, &self->ctx); } else { // Initiate write transaction - result = Cy_SCB_I2C_MasterWrite(MICROPY_HW_I2C0_SCB, &transfer, &machine_hw_i2c_ctx[i2c_id]); + result = Cy_SCB_I2C_MasterWrite(MICROPY_HW_I2C0_SCB, &transfer, &self->ctx); } if (result != CY_RSLT_SUCCESS) { @@ -274,7 +240,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Wait for transaction completion // The interrupt handler (Cy_SCB_I2C_MasterInterrupt) processes the transaction uint32_t timeout = 100000; // Timeout counter - while (0UL != (CY_SCB_I2C_MASTER_BUSY & Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]))) { + while (0UL != (CY_SCB_I2C_MASTER_BUSY & Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &self->ctx))) { // Yield to allow other tasks/interrupts to run MICROPY_EVENT_POLL_HOOK if (--timeout == 0) { @@ -284,7 +250,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t } // Check if there were any errors during the transfer - uint32_t master_status = Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &machine_hw_i2c_ctx[i2c_id]); + uint32_t master_status = Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &self->ctx); mp_printf(&mp_plat_print, "I2C Transfer complete, status=0x%08lX\n", master_status); From 7cb6cd364ac5bfc0600277e9c602ee5c45d774d6 Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Wed, 10 Dec 2025 11:29:04 +0100 Subject: [PATCH 4/7] psoc-edge/machine_i2c: Add logging functionality. Signed-off-by: zhanglinjing --- ports/psoc-edge/machine_i2c.c | 22 +++++++++--------- ports/psoc-edge/mpconfigport.h | 3 +++ ports/psoc-edge/mplogger.h | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 ports/psoc-edge/mplogger.h diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index d5266ac6b794e..b9c2fb2ace4ae 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -46,7 +46,7 @@ // port-specific includes #include "modmachine.h" // #include "machine_pin_phy.h" -// #include "mplogger.h" +#include "mplogger.h" #include "machine_i2c.h" // TODO: Add pin define #define DEFAULT_I2C_FREQ (400000) @@ -89,9 +89,9 @@ static inline machine_hw_i2c_obj_t *machine_hw_i2c_obj_alloc(void) { } // Debug: print status of all slots - mp_printf(&mp_plat_print, "I2C alloc failed - all slots occupied:\n"); + mplogger_print(&mp_plat_print, "I2C alloc failed - all slots occupied:\n"); for (uint8_t i = 0; i < MAX_I2C; i++) { - mp_printf(&mp_plat_print, " Slot %u: %p\n", i, machine_hw_i2c_obj[i]); + mplogger_print(&mp_plat_print, " Slot %u: %p\n", i, machine_hw_i2c_obj[i]); } return NULL; @@ -151,10 +151,10 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { // 5. Configure master data rate uint32_t clk_scb_freq = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 2U); - mp_printf(&mp_plat_print, "DEBUG: clk_scb_freq=%u Hz\n", clk_scb_freq); + mplogger_print(&mp_plat_print, "DEBUG: clk_scb_freq=%u Hz\n", clk_scb_freq); uint32_t actual_rate = Cy_SCB_I2C_SetDataRate(MICROPY_HW_I2C0_SCB, freq_hz, clk_scb_freq); - mp_printf(&mp_plat_print, "DEBUG: actual_rate=%u Hz (requested=%u Hz)\n", actual_rate, freq_hz); + mplogger_print(&mp_plat_print, "DEBUG: actual_rate=%u Hz (requested=%u Hz)\n", actual_rate, freq_hz); if ((actual_rate > freq_hz) || (actual_rate == 0U)) { mp_raise_msg_varg(&mp_type_ValueError, @@ -210,7 +210,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); cy_rslt_t result; - mp_printf(&mp_plat_print, "I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", + mplogger_print(&mp_plat_print, "I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", addr, len, flags, (flags & MP_MACHINE_I2C_FLAG_READ) ? "READ" : "WRITE"); // Configure transfer structure @@ -231,11 +231,11 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t } if (result != CY_RSLT_SUCCESS) { - mp_printf(&mp_plat_print, "I2C Transfer start failed: 0x%lx\n", result); + mplogger_print(&mp_plat_print, "I2C Transfer start failed: 0x%lx\n", result); return -MP_EIO; // I/O error } - mp_printf(&mp_plat_print, "I2C Transfer started, waiting for completion...\n"); + mplogger_print(&mp_plat_print, "I2C Transfer started, waiting for completion...\n"); // Wait for transaction completion // The interrupt handler (Cy_SCB_I2C_MasterInterrupt) processes the transaction @@ -244,7 +244,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Yield to allow other tasks/interrupts to run MICROPY_EVENT_POLL_HOOK if (--timeout == 0) { - mp_printf(&mp_plat_print, "I2C Transfer timeout!\n"); + mplogger_print(&mp_plat_print, "I2C Transfer timeout!\n"); return -MP_ETIMEDOUT; } } @@ -252,11 +252,11 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Check if there were any errors during the transfer uint32_t master_status = Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &self->ctx); - mp_printf(&mp_plat_print, "I2C Transfer complete, status=0x%08lX\n", master_status); + mplogger_print(&mp_plat_print, "I2C Transfer complete, status=0x%08lX\n", master_status); if (master_status & CY_SCB_I2C_MASTER_ERR) { // Error occurred during transfer - mp_printf(&mp_plat_print, "I2C Transfer error detected in status\n"); + mplogger_print(&mp_plat_print, "I2C Transfer error detected in status\n"); return -MP_EIO; // I/O error } diff --git a/ports/psoc-edge/mpconfigport.h b/ports/psoc-edge/mpconfigport.h index 527510fcca2d8..3c254975ef3ae 100644 --- a/ports/psoc-edge/mpconfigport.h +++ b/ports/psoc-edge/mpconfigport.h @@ -69,6 +69,9 @@ #define MICROPY_PY_TIME_TIME_TIME_NS (1) #define MICROPY_PY_TIME_INCLUDEFILE "ports/psoc-edge/modtime.c" +// Logger +#define MICROPY_LOGGER_DEBUG (1) + // Machine module #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_INCLUDEFILE "ports/psoc-edge/modmachine.c" diff --git a/ports/psoc-edge/mplogger.h b/ports/psoc-edge/mplogger.h new file mode 100644 index 0000000000000..4bd6bb29d90c9 --- /dev/null +++ b/ports/psoc-edge/mplogger.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2022-2024 Infineon Technologies AG + * + * 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. + */ + + +// Logger module to pass messages to console. + + +// macro to pipe debug messages to console in LOGGER DEBUG MODE +// TODO: Since this is an expensive function call when LOGGER DEBUG mode is not activated, +// a rework of this function needed similar to MPY's built-in debug message handler DEBUG_print() +// Conditional debug logging macro +// Enable/disable with MICROPY_LOGGER_DEBUG in mpconfigport.h +#if MICROPY_LOGGER_DEBUG +#define mplogger_print(...) mp_printf(__VA_ARGS__) +#else +#define mplogger_print(...) // No-op when debug is disabled +#endif From 1e56330577d10e6840fb0dd550335dc2d44e36b3 Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Wed, 10 Dec 2025 11:36:36 +0100 Subject: [PATCH 5/7] psoc-edge/machine_i2c: Move specific config to mpconfigboard.h. Signed-off-by: zhanglinjing --- ports/psoc-edge/boards/KIT_PSE84_AI/mpconfigboard.h | 9 +++++++++ ports/psoc-edge/machine_i2c.c | 11 +++++------ ports/psoc-edge/machine_i2c.h | 8 -------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ports/psoc-edge/boards/KIT_PSE84_AI/mpconfigboard.h b/ports/psoc-edge/boards/KIT_PSE84_AI/mpconfigboard.h index 622415ab2e80d..f357946cdf032 100644 --- a/ports/psoc-edge/boards/KIT_PSE84_AI/mpconfigboard.h +++ b/ports/psoc-edge/boards/KIT_PSE84_AI/mpconfigboard.h @@ -31,3 +31,12 @@ #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "KIT_PSE84_AI" #define MICROPY_GC_HEAP_SIZE (315 * 1024) // 315 KB + +// I2C Configuration +#define MICROPY_HW_I2C0_SCB (SCB5) +#define MICROPY_HW_I2C0_SCL (P17_0_NUM) +#define MICROPY_HW_I2C0_SDA (P17_1_NUM) +#define MAX_I2C 1 +#define MICROPY_HW_I2C_INTR_PRIORITY (7UL) +#define MICROPY_HW_I2C_PCLK PCLK_SCB5_CLOCK_SCB_EN +#define MICROPY_HW_I2C_IRQn scb_5_interrupt_IRQn diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index b9c2fb2ace4ae..bbad3147b8f45 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -144,7 +144,7 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { // - clk_peri = 100 MHz, divider = 11 → clk_scb = 9.09 MHz ✓ (within range) // Note: Cy_SysClk_PeriphSetDivider takes (divider - 1), so divider=11 → value=10 /* Connect assigned divider to be a clock source for I2C */ - Cy_SysClk_PeriphAssignDivider(PCLK_SCB5_CLOCK_SCB_EN, CY_SYSCLK_DIV_8_BIT, 2U); + Cy_SysClk_PeriphAssignDivider(MICROPY_HW_I2C_PCLK, CY_SYSCLK_DIV_8_BIT, 2U); uint32_t divider = (freq_hz <= 100000) ? 41U : 10U; Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 2U, divider); Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 2U); @@ -164,10 +164,9 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { // 6. Configure interrupt (mandatory for I2C operation) // Populate interrupt configuration structure - #define I2C_INTR_PRIORITY (7UL) const cy_stc_sysint_t i2cIntrConfig = { - .intrSrc = scb_5_interrupt_IRQn, - .intrPriority = I2C_INTR_PRIORITY, + .intrSrc = MICROPY_HW_I2C_IRQn, + .intrPriority = MICROPY_HW_I2C_INTR_PRIORITY, }; // Hook interrupt service routine and enable interrupt in NVIC @@ -175,7 +174,7 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { if (result != CY_RSLT_SUCCESS) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C interrupt init failed: 0x%lx"), result); } - NVIC_EnableIRQ(scb_5_interrupt_IRQn); + NVIC_EnableIRQ(MICROPY_HW_I2C_IRQn); // 7. Enable I2C operation Cy_SCB_I2C_Enable(MICROPY_HW_I2C0_SCB); @@ -195,7 +194,7 @@ static int machine_hw_i2c_deinit(mp_obj_base_t *self_in) { Cy_SCB_I2C_Disable(MICROPY_HW_I2C0_SCB, &self->ctx); // Disable interrupt in NVIC - NVIC_DisableIRQ(scb_5_interrupt_IRQn); + NVIC_DisableIRQ(MICROPY_HW_I2C_IRQn); // Disable clock divider Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_8_BIT, 0U); diff --git a/ports/psoc-edge/machine_i2c.h b/ports/psoc-edge/machine_i2c.h index 692bd34691ef8..4c29783be2fa9 100644 --- a/ports/psoc-edge/machine_i2c.h +++ b/ports/psoc-edge/machine_i2c.h @@ -27,14 +27,6 @@ #ifndef MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H #define MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H -// Configure default I2C0 pins and SCB peripheral -#ifndef MICROPY_HW_I2C0_SCL -#define MICROPY_HW_I2C0_SCB (SCB5) -#define MICROPY_HW_I2C0_SCL (P17_0_NUM) -#define MICROPY_HW_I2C0_SDA (P17_1_NUM) -#define MAX_I2C 1 -#endif - // Declare the I2C type for external use extern const mp_obj_type_t machine_i2c_type; From 48584c4f28f442c4943aadc08720433b8574328f Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Wed, 10 Dec 2025 13:38:12 +0100 Subject: [PATCH 6/7] posc-edge: Reuse mplogger. Signed-off-by: zhanglinjing --- ports/psoc-edge/mplogger.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ports/psoc-edge/mplogger.h b/ports/psoc-edge/mplogger.h index 4bd6bb29d90c9..bf43dcc987e1a 100644 --- a/ports/psoc-edge/mplogger.h +++ b/ports/psoc-edge/mplogger.h @@ -32,10 +32,5 @@ // macro to pipe debug messages to console in LOGGER DEBUG MODE // TODO: Since this is an expensive function call when LOGGER DEBUG mode is not activated, // a rework of this function needed similar to MPY's built-in debug message handler DEBUG_print() -// Conditional debug logging macro -// Enable/disable with MICROPY_LOGGER_DEBUG in mpconfigport.h -#if MICROPY_LOGGER_DEBUG -#define mplogger_print(...) mp_printf(__VA_ARGS__) -#else -#define mplogger_print(...) // No-op when debug is disabled -#endif +#define mplogger_print(...) \ + do { if (MICROPY_LOGGER_DEBUG) mp_printf(&mp_plat_print, __VA_ARGS__); } while (0) From 669f67114d24503fc45c230d73292223d3311a27 Mon Sep 17 00:00:00 2001 From: zhanglinjing Date: Wed, 10 Dec 2025 13:40:13 +0100 Subject: [PATCH 7/7] psoc-edge/machine_i2c: Remove unnecessary header and improve code. Signed-off-by: zhanglinjing --- ports/psoc-edge/machine_i2c.c | 56 +++++++++++++++++++++++++---------- ports/psoc-edge/machine_i2c.h | 33 --------------------- 2 files changed, 40 insertions(+), 49 deletions(-) delete mode 100644 ports/psoc-edge/machine_i2c.h diff --git a/ports/psoc-edge/machine_i2c.c b/ports/psoc-edge/machine_i2c.c index bbad3147b8f45..ae0c410bc11e9 100644 --- a/ports/psoc-edge/machine_i2c.c +++ b/ports/psoc-edge/machine_i2c.c @@ -47,7 +47,6 @@ #include "modmachine.h" // #include "machine_pin_phy.h" #include "mplogger.h" -#include "machine_i2c.h" // TODO: Add pin define #define DEFAULT_I2C_FREQ (400000) @@ -89,9 +88,9 @@ static inline machine_hw_i2c_obj_t *machine_hw_i2c_obj_alloc(void) { } // Debug: print status of all slots - mplogger_print(&mp_plat_print, "I2C alloc failed - all slots occupied:\n"); + mplogger_print("I2C alloc failed - all slots occupied:\n"); for (uint8_t i = 0; i < MAX_I2C; i++) { - mplogger_print(&mp_plat_print, " Slot %u: %p\n", i, machine_hw_i2c_obj[i]); + mplogger_print(" Slot %u: %p\n", i, machine_hw_i2c_obj[i]); } return NULL; @@ -151,10 +150,10 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq_hz) { // 5. Configure master data rate uint32_t clk_scb_freq = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 2U); - mplogger_print(&mp_plat_print, "DEBUG: clk_scb_freq=%u Hz\n", clk_scb_freq); + mplogger_print("DEBUG: clk_scb_freq=%u Hz\n", clk_scb_freq); uint32_t actual_rate = Cy_SCB_I2C_SetDataRate(MICROPY_HW_I2C0_SCB, freq_hz, clk_scb_freq); - mplogger_print(&mp_plat_print, "DEBUG: actual_rate=%u Hz (requested=%u Hz)\n", actual_rate, freq_hz); + mplogger_print("DEBUG: actual_rate=%u Hz (requested=%u Hz)\n", actual_rate, freq_hz); if ((actual_rate > freq_hz) || (actual_rate == 0U)) { mp_raise_msg_varg(&mp_type_ValueError, @@ -209,7 +208,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t machine_hw_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); cy_rslt_t result; - mplogger_print(&mp_plat_print, "I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", + mplogger_print("I2C Transfer: addr=0x%02X, len=%u, flags=0x%02X (%s)\n", addr, len, flags, (flags & MP_MACHINE_I2C_FLAG_READ) ? "READ" : "WRITE"); // Configure transfer structure @@ -230,11 +229,11 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t } if (result != CY_RSLT_SUCCESS) { - mplogger_print(&mp_plat_print, "I2C Transfer start failed: 0x%lx\n", result); + mplogger_print("I2C Transfer start failed: 0x%lx\n", result); return -MP_EIO; // I/O error } - mplogger_print(&mp_plat_print, "I2C Transfer started, waiting for completion...\n"); + mplogger_print("I2C Transfer started, waiting for completion...\n"); // Wait for transaction completion // The interrupt handler (Cy_SCB_I2C_MasterInterrupt) processes the transaction @@ -243,7 +242,7 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Yield to allow other tasks/interrupts to run MICROPY_EVENT_POLL_HOOK if (--timeout == 0) { - mplogger_print(&mp_plat_print, "I2C Transfer timeout!\n"); + mplogger_print("I2C Transfer timeout!\n"); return -MP_ETIMEDOUT; } } @@ -251,11 +250,11 @@ static int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t // Check if there were any errors during the transfer uint32_t master_status = Cy_SCB_I2C_MasterGetStatus(MICROPY_HW_I2C0_SCB, &self->ctx); - mplogger_print(&mp_plat_print, "I2C Transfer complete, status=0x%08lX\n", master_status); + mplogger_print("I2C Transfer complete, status=0x%08lX\n", master_status); if (master_status & CY_SCB_I2C_MASTER_ERR) { // Error occurred during transfer - mplogger_print(&mp_plat_print, "I2C Transfer error detected in status\n"); + mplogger_print("I2C Transfer error detected in status\n"); return -MP_EIO; // I/O error } @@ -292,7 +291,23 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ 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); - machine_hw_i2c_obj_t *self = machine_hw_i2c_obj_alloc(); + // Check if an I2C instance already exists for this ID + // If so, deinitialize it first (allows reinitialization) + int requested_id = args[ARG_id].u_int; + if (requested_id == -1) { + requested_id = 0; // Default to ID 0 + } + + // For single I2C port, reuse the existing object if present + machine_hw_i2c_obj_t *self = machine_hw_i2c_obj[0]; + if (self != NULL) { + // Deinitialize existing instance + mplogger_print("Reinitializing existing I2C instance\n"); + machine_hw_i2c_deinit((mp_obj_base_t *)self); + } + + // Allocate new instance + self = machine_hw_i2c_obj_alloc(); if (self == NULL) { mp_raise_ValueError(MP_ERROR_TEXT("Maximum number of I2C instances reached")); } @@ -303,21 +318,30 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ mp_printf(&mp_plat_print, "machine.I2C: ID parameter is ignored in this port.\n"); } - // Parse and validate pin arguments, use defaults from machine_i2c.h if not provided + // Parse and validate pin arguments, use defaults from mpconfigboard.h if not provided if (args[ARG_scl].u_obj != MP_ROM_NONE) { self->scl_pin = mp_obj_get_int(args[ARG_scl].u_obj); } else { - self->scl_pin = MICROPY_HW_I2C0_SCL; // Default from machine_i2c.h + self->scl_pin = MICROPY_HW_I2C0_SCL; // Default from mpconfigboard.h } if (args[ARG_sda].u_obj != MP_ROM_NONE) { self->sda_pin = mp_obj_get_int(args[ARG_sda].u_obj); } else { - self->sda_pin = MICROPY_HW_I2C0_SDA; // Default from machine_i2c.h + self->sda_pin = MICROPY_HW_I2C0_SDA; // Default from mpconfigboard.h } // initialise I2C at hardware level - machine_hw_i2c_init(self, args[ARG_freq].u_int); + // If this fails, free the allocated object + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + machine_hw_i2c_init(self, args[ARG_freq].u_int); + nlr_pop(); + } else { + // Initialization failed, clean up + machine_hw_i2c_obj_free(self); + nlr_jump(nlr.ret_val); + } return MP_OBJ_FROM_PTR(self); } diff --git a/ports/psoc-edge/machine_i2c.h b/ports/psoc-edge/machine_i2c.h deleted file mode 100644 index 4c29783be2fa9..0000000000000 --- a/ports/psoc-edge/machine_i2c.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019-2025 Damien P. George - * - * 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. - */ -#ifndef MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H -#define MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H - -// Declare the I2C type for external use -extern const mp_obj_type_t machine_i2c_type; - -#endif // MICROPY_INCLUDED_PSOCEDGE_MACHINE_I2C_H