From 98c5703027e7db9a030f747f4dd1684407230656 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Sat, 19 Jun 2021 22:09:40 +0200 Subject: [PATCH] mimxrt/machine_i2c: Add hardware-based machine.I2C to machine module. It uses non-blocking transfer of data. Advantage over SoftI2C: - Higher data rate up to ~3 MHZ. - Full protocol support. --- ports/mimxrt/Makefile | 2 + .../boards/MIMXRT1010_EVK/mpconfigboard.h | 12 + .../boards/MIMXRT1020_EVK/mpconfigboard.h | 17 +- .../boards/MIMXRT1050_EVK/mpconfigboard.h | 12 + .../boards/MIMXRT1060_EVK/mpconfigboard.h | 12 + .../boards/MIMXRT1064_EVK/mpconfigboard.h | 12 + ports/mimxrt/boards/TEENSY40/mpconfigboard.h | 14 ++ ports/mimxrt/boards/TEENSY41/mpconfigboard.h | 14 ++ ports/mimxrt/machine_i2c.c | 217 ++++++++++++++++++ ports/mimxrt/modmachine.c | 1 + ports/mimxrt/modmachine.h | 1 + 11 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 ports/mimxrt/machine_i2c.c diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 64d9864cbb..580dc32c7e 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -123,6 +123,7 @@ SRC_HAL_IMX_C += \ $(MCU_DIR)/drivers/fsl_gpio.c \ $(MCU_DIR)/drivers/fsl_gpt.c \ $(MCU_DIR)/drivers/fsl_common.c \ + $(MCU_DIR)/drivers/fsl_lpi2c.c \ $(MCU_DIR)/drivers/fsl_lpspi.c \ $(MCU_DIR)/drivers/fsl_lpspi_edma.c \ $(MCU_DIR)/drivers/fsl_lpuart.c \ @@ -142,6 +143,7 @@ SRC_C = \ dma_channel.c \ $(BOARD_DIR)/flash_config.c \ machine_adc.c \ + machine_i2c.c \ machine_led.c \ machine_pin.c \ machine_rtc.c \ diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h index 3576706264..756eaf85eb 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h @@ -33,3 +33,15 @@ #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx } + +// Define mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// D14/D15 LPI2C1 -> 0 +// D0/D1 LPI2C2 -> 1 +// D6/D7 LPI2C2 -> 1 Alternatively possible GPIO_AD_01, GPIO_AD_02 + +#define MICROPY_HW_I2C_INDEX { 1, 2 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_02_LPI2C1_SCL }, { IOMUXC_GPIO_01_LPI2C1_SDA }, \ + { IOMUXC_GPIO_10_LPI2C2_SCL }, { IOMUXC_GPIO_09_LPI2C2_SDA }, diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h index 55254d58f6..b0574fad0f 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h @@ -13,7 +13,8 @@ #define MICROPY_HW_NUM_PIN_IRQS (3 * 32) // Define mapping logical UART # to hardware UART # -// D3/D5 LPUART1 Not usable, Since D3 is blocked. +// RX/TX HW-UART Logical UART +// D3/D5 LPUART1 Not usable, Since D3 is blocked. // D0/D1 LPUART2 -> 1 // D6/D9 LPUART3 -> 2 // D10/D12 LPUART5 -> 3 @@ -48,3 +49,17 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// D14/D15 LPI2C4 -> 0 +// A4/A5 LPI2C1 -> 1 +// D0/D1 LPI2C2 -> 2 + +#define MICROPY_HW_I2C_INDEX { 4, 1, 2 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_14_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_15_LPI2C1_SDA }, \ + { IOMUXC_GPIO_AD_B1_08_LPI2C2_SCL }, { IOMUXC_GPIO_AD_B1_09_LPI2C2_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B1_02_LPI2C4_SCL }, { IOMUXC_GPIO_SD_B1_03_LPI2C4_SDA }, diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h index db08b1064d..5d920d5286 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h @@ -41,3 +41,15 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define the mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// D14/D15 LPI2C1 -> 0 +// D1/D0 LPI2C3 -> 1 + +#define MICROPY_HW_I2C_INDEX { 1, 3 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h index 451d53dafd..f849cba966 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h @@ -41,3 +41,15 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define the mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// D14/D15 LPI2C1 -> 0 +// D1/D0 LPI2C3 -> 1 + +#define MICROPY_HW_I2C_INDEX { 1, 3 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h index e300efef32..2301f34131 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h @@ -39,3 +39,15 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define the mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// D14/D15 LPI2C1 -> 0 +// D1/D0 LPI2C3 -> 1 + +#define MICROPY_HW_I2C_INDEX { 1, 3 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h index 8b38d047f8..b6c81a4229 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h @@ -42,3 +42,17 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// 17/16 LPI2C3 -> 0 +// 18/19 LPI2C1 -> 1 +// 25/24 LPI2C4 -> 2 + +#define MICROPY_HW_I2C_INDEX { 1, 3, 4 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \ + { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA }, diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h index 455bf8d69c..17d2751682 100644 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h @@ -42,3 +42,17 @@ #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// 17/16 LPI2C3 -> 0 +// 18/19 LPI2C1 -> 1 +// 25/24 LPI2C4 -> 2 + +#define MICROPY_HW_I2C_INDEX { 1, 3, 4 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \ + { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA }, diff --git a/ports/mimxrt/machine_i2c.c b/ports/mimxrt/machine_i2c.c new file mode 100644 index 0000000000..618d0a2581 --- /dev/null +++ b/ports/mimxrt/machine_i2c.c @@ -0,0 +1,217 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 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. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "extmod/machine_i2c.h" +#include "modmachine.h" + +#include "fsl_iomuxc.h" +#include "fsl_lpi2c.h" + +#define DEFAULT_I2C_FREQ (400000) +#define DEFAULT_I2C_DRIVE (6) + +// Select USB1 PLL (480 MHz) as master lpi2c clock source +#define LPI2C_CLOCK_SOURCE_SELECT (0U) +// Clock divider for master lpi2c clock source +#define LPI2C_CLOCK_SOURCE_DIVIDER (1U) +// Get frequency of lpi2c clock = 30 MHz +#define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) + +typedef struct _machine_i2c_obj_t { + mp_obj_base_t base; + LPI2C_Type *i2c_inst; + uint8_t i2c_id; + uint8_t i2c_hw_id; + bool transfer_busy; + status_t transfer_status; + lpi2c_master_config_t *master_config; +} machine_i2c_obj_t; + +typedef struct _iomux_table_t { + uint32_t muxRegister; + uint32_t muxMode; + uint32_t inputRegister; + uint32_t inputDaisy; + 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; +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]) + +bool lpi2c_set_iomux(int8_t hw_i2c, uint8_t drive) { + int index = (hw_i2c - 1) * 2; + + if (SCL.muxRegister != 0) { + IOMUXC_SetPinMux(SCL.muxRegister, SCL.muxMode, SCL.inputRegister, SCL.inputDaisy, SCL.configRegister, 1U); + IOMUXC_SetPinConfig(SCL.muxRegister, SCL.muxMode, SCL.inputRegister, SCL.inputDaisy, SCL.configRegister, + 0xF880u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT); + + IOMUXC_SetPinMux(SDA.muxRegister, SDA.muxMode, SDA.inputRegister, SDA.inputDaisy, SDA.configRegister, 1U); + IOMUXC_SetPinConfig(SDA.muxRegister, SDA.muxMode, SDA.inputRegister, SDA.inputDaisy, SDA.configRegister, + 0xF880u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT); + return true; + } else { + return false; + } +} + +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(%u, freq=%u)", + self->i2c_id, self->master_config->baudRate_Hz); +} + +mp_obj_t machine_i2c_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_freq, ARG_drive}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_freq, MP_ARG_INT, {.u_int = DEFAULT_I2C_FREQ} }, + { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_I2C_DRIVE} }, + }; + + static bool clk_init = true; + + // 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); + + // Get I2C bus. + int i2c_id = mp_obj_get_int(args[ARG_id].u_obj); + if (i2c_id < 0 || i2c_id >= MICROPY_HW_I2C_NUM) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id); + } + + // Get I2C Object. + machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t); + self->base.type = &machine_i2c_type; + self->i2c_id = i2c_id; + self->i2c_hw_id = i2c_index_table[i2c_id]; // the hw i2c number 1..n + self->i2c_inst = i2c_base_ptr_table[self->i2c_hw_id]; + + uint8_t drive = args[ARG_drive].u_int; + if (drive < 1 || drive > 7) { + drive = DEFAULT_I2C_DRIVE; + } + + if (clk_init) { + clk_init = false; + // Set clock source for LPI2C + CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT); // USB1 PLL (480 MHz) + CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER); + } + + // Initialise the I2C peripheral if any arguments given, or it was not initialised previously. + lpi2c_set_iomux(self->i2c_hw_id, drive); + self->master_config = m_new_obj(lpi2c_master_config_t); + LPI2C_MasterGetDefaultConfig(self->master_config); + // Initialise the I2C peripheral. + self->master_config->baudRate_Hz = args[ARG_freq].u_int; + LPI2C_MasterInit(self->i2c_inst, self->master_config, LPI2C_CLOCK_FREQUENCY); + + return MP_OBJ_FROM_PTR(self); +} + +static void lpi2c_master_callback(LPI2C_Type *base, lpi2c_master_handle_t *handle, status_t status, void *self_in) { + machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in; + + self->transfer_busy = false; + self->transfer_status = status; +} + +STATIC int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { + machine_i2c_obj_t *self = (machine_i2c_obj_t *)self_in; + status_t ret; + lpi2c_master_handle_t g_master_handle; + lpi2c_master_transfer_t masterXfer = {0}; + LPI2C_MasterTransferCreateHandle(self->i2c_inst, &g_master_handle, lpi2c_master_callback, self); + + if (flags & MP_MACHINE_I2C_FLAG_READ) { + masterXfer.direction = kLPI2C_Read; + } else { + masterXfer.direction = kLPI2C_Write; + } + if (addr < 0x80) { // 7 or 10 bit address? + masterXfer.slaveAddress = addr; + } else { + masterXfer.slaveAddress = 0x78 | ((addr >> 8) & 0x03); + masterXfer.subaddress = addr & 0xff; + masterXfer.subaddressSize = 1; + } + masterXfer.data = buf; + masterXfer.dataSize = len; + if (flags & MP_MACHINE_I2C_FLAG_STOP) { + masterXfer.flags = kLPI2C_TransferDefaultFlag; + } else { + masterXfer.flags = kLPI2C_TransferNoStopFlag; + } + self->transfer_busy = true; + + // Send master data to slave in non-blocking mode + ret = LPI2C_MasterTransferNonBlocking(self->i2c_inst, &g_master_handle, &masterXfer); + if (ret != kStatus_Success) { + return -MP_EIO; + } + // Wait for the transfer to complete + while (self->transfer_busy) { + MICROPY_EVENT_POLL_HOOK + } + + // Transfer will not send a stop in case of errors like NAK. So it's done here. + if (flags & MP_MACHINE_I2C_FLAG_STOP && self->transfer_status != kStatus_Success) { + LPI2C_MasterStop(self->i2c_inst); + } + + if (self->transfer_status == kStatus_Success) { + return len; + } else if (self->transfer_status == kStatus_LPI2C_Nak) { + return -MP_ENODEV; + } else { + return -MP_EIO; + } +} + +STATIC const mp_machine_i2c_p_t machine_i2c_p = { + .transfer = mp_machine_i2c_transfer_adaptor, + .transfer_single = machine_i2c_transfer_single, +}; + +const mp_obj_type_t machine_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_i2c_print, + .make_new = machine_i2c_make_new, + .protocol = &machine_i2c_p, + .locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict, +}; diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c index e821f15070..150615ca03 100644 --- a/ports/mimxrt/modmachine.c +++ b/ports/mimxrt/modmachine.c @@ -85,6 +85,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index eba8e6db8f..9732093bd8 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -32,6 +32,7 @@ extern const mp_obj_type_t machine_adc_type; extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_rtc_type; +extern const mp_obj_type_t machine_i2c_type; extern const mp_obj_type_t machine_spi_type; extern const mp_obj_type_t machine_uart_type;