diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 647cf04044..5ad43a1ed2 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -369,7 +369,9 @@ msgstr "" msgid "All CAN peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c ports/nrf/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c +#: ports/nrf/common-hal/busio/I2C.c msgid "All I2C peripherals are in use" msgstr "" @@ -1301,8 +1303,11 @@ msgstr "" msgid "Invalid Pin" msgstr "" -#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c shared-module/rgbmatrix/RGBMatrix.c +#: ports/espressif/bindings/espidf/__init__.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c +#: ports/espressif/esp_error.c py/moduerrno.c +#: shared-module/rgbmatrix/RGBMatrix.c msgid "Invalid argument" msgstr "" @@ -1350,10 +1355,6 @@ msgstr "" msgid "Invalid format chunk size" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Invalid frequency" -msgstr "" - #: supervisor/shared/safe_mode.c msgid "Invalid memory access." msgstr "" @@ -1394,6 +1395,7 @@ msgstr "" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/busio/UART.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c #: ports/mimxrt10xx/common-hal/busio/I2C.c #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/busio/I2C.c @@ -1771,6 +1773,10 @@ msgstr "" msgid "Only one TouchAlarm can be set in deep sleep." msgstr "" +#: ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c +msgid "Only one address is allowed" +msgstr "" + #: ports/espressif/common-hal/alarm/time/TimeAlarm.c #: ports/nrf/common-hal/alarm/time/TimeAlarm.c #: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index b2f350c7c7..c26f2ebffb 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -219,6 +219,7 @@ SRC_C += \ boards/$(BOARD)/pins.c \ modules/$(CIRCUITPY_MODULE).c \ lib/netutils/netutils.c \ + peripherals/i2c.c \ peripherals/rmt.c \ peripherals/timer.c \ peripherals/$(IDF_TARGET)/pins.c diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index be80538582..81b23cb3a3 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -34,26 +34,6 @@ #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/translate.h" -typedef enum { - STATUS_FREE = 0, - STATUS_IN_USE, - STATUS_NEVER_RESET -} i2c_status_t; - -static i2c_status_t i2c_status[I2C_NUM_MAX]; - -void never_reset_i2c(i2c_port_t num) { - i2c_status[num] = STATUS_NEVER_RESET; -} - -void i2c_reset(void) { - for (i2c_port_t num = 0; num < I2C_NUM_MAX; num++) { - if (i2c_status[num] == STATUS_IN_USE) { - i2c_status[num] = STATUS_FREE; - } - } -} - void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { // Pins 45 and 46 are "strapping" pins that impact start up behavior. They usually need to @@ -99,21 +79,16 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, } self->sda_pin = sda; self->scl_pin = scl; - self->i2c_num = I2C_NUM_MAX; - for (i2c_port_t num = 0; num < I2C_NUM_MAX; num++) { - if (i2c_status[num] == STATUS_FREE) { - self->i2c_num = num; - } - } + self->i2c_num = peripherals_i2c_get_free_num(); + if (self->i2c_num == I2C_NUM_MAX) { mp_raise_ValueError(translate("All I2C peripherals are in use")); } - i2c_status[self->i2c_num] = STATUS_IN_USE; // Delete any previous driver. i2c_driver_delete(self->i2c_num); - i2c_config_t i2c_conf = { + const i2c_config_t i2c_conf = { .mode = I2C_MODE_MASTER, .sda_io_num = self->sda_pin->number, .scl_io_num = self->scl_pin->number, @@ -129,16 +104,15 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, .clk_speed = frequency, } }; - if (i2c_param_config(self->i2c_num, &i2c_conf) != ESP_OK) { - mp_raise_ValueError(translate("Invalid frequency")); - } - if (i2c_driver_install(self->i2c_num, - I2C_MODE_MASTER, - 0, - 0, - 0) != ESP_OK) { - mp_raise_OSError(MP_EIO); + // Initialize I2C. + esp_err_t err = peripherals_i2c_init(self->i2c_num, &i2c_conf); + if (err != ESP_OK) { + if (err == ESP_FAIL) { + mp_raise_OSError(MP_EIO); + } else { + mp_raise_ValueError(translate("Invalid argument")); + } } claim_pin(sda); @@ -154,14 +128,12 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { return; } - i2c_driver_delete(self->i2c_num); + peripherals_i2c_deinit(self->i2c_num); common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); self->sda_pin = NULL; self->scl_pin = NULL; - - i2c_status[self->i2c_num] = STATUS_FREE; } bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { diff --git a/ports/espressif/common-hal/busio/I2C.h b/ports/espressif/common-hal/busio/I2C.h index a44c414505..e3e60c07be 100644 --- a/ports/espressif/common-hal/busio/I2C.h +++ b/ports/espressif/common-hal/busio/I2C.h @@ -34,6 +34,8 @@ #include "freertos/semphr.h" #include "py/obj.h" +#include "peripherals/i2c.h" + typedef struct { mp_obj_base_t base; const mcu_pin_obj_t *scl_pin; @@ -43,6 +45,4 @@ typedef struct { bool has_lock; } busio_i2c_obj_t; -void i2c_reset(void); - #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_BUSIO_I2C_H diff --git a/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c b/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c new file mode 100644 index 0000000000..d073a8a362 --- /dev/null +++ b/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.c @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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 "shared-bindings/i2cperipheral/I2CPeripheral.h" + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "common-hal/i2cperipheral/I2CPeripheral.h" + +void common_hal_i2cperipheral_i2c_peripheral_construct(i2cperipheral_i2c_peripheral_obj_t *self, + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, + uint8_t *addresses, unsigned int num_addresses, bool smbus) { + // Pins 45 and 46 are "strapping" pins that impact start up behavior. They usually need to + // be pulled-down so pulling them up for I2C is a bad idea. To make this hard, we don't + // support I2C on these pins. + // Also 46 is input-only so it'll never work. + if (scl->number == 45 || scl->number == 46 || sda->number == 45 || sda->number == 46) { + mp_raise_ValueError(translate("Invalid pins")); + } + + if (num_addresses > 1) { + mp_raise_ValueError(translate("Only one address is allowed")); + } + self->addresses = addresses; + self->num_addresses = num_addresses; + + self->sda_pin = sda; + self->scl_pin = scl; + self->i2c_num = peripherals_i2c_get_free_num(); + + if (self->i2c_num == I2C_NUM_MAX) { + mp_raise_ValueError(translate("All I2C peripherals are in use")); + } + + const i2c_config_t i2c_conf = { + .mode = I2C_MODE_SLAVE, + .sda_io_num = self->sda_pin->number, + .scl_io_num = self->scl_pin->number, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .slave.addr_10bit_en = 0, + .slave.slave_addr = self->addresses[0], + }; + + // Initialize I2C. + esp_err_t err = peripherals_i2c_init(self->i2c_num, &i2c_conf); + if (err != ESP_OK) { + if (err == ESP_FAIL) { + mp_raise_OSError(MP_EIO); + } else { + mp_raise_ValueError(translate("Invalid argument")); + } + } + + claim_pin(sda); + claim_pin(scl); +} + +bool common_hal_i2cperipheral_i2c_peripheral_deinited(i2cperipheral_i2c_peripheral_obj_t *self) { + return self->sda_pin == NULL; +} + +void common_hal_i2cperipheral_i2c_peripheral_deinit(i2cperipheral_i2c_peripheral_obj_t *self) { + if (common_hal_i2cperipheral_i2c_peripheral_deinited(self)) { + return; + } + + peripherals_i2c_deinit(self->i2c_num); + + common_hal_reset_pin(self->sda_pin); + common_hal_reset_pin(self->scl_pin); + self->sda_pin = NULL; + self->scl_pin = NULL; +} + +int common_hal_i2cperipheral_i2c_peripheral_is_addressed(i2cperipheral_i2c_peripheral_obj_t *self, + uint8_t *address, bool *is_read, bool *is_restart) { + *address = self->addresses[0]; + *is_read = true; + *is_restart = false; + return 1; +} + +int common_hal_i2cperipheral_i2c_peripheral_read_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t *data) { + i2c_slave_read_buffer(self->i2c_num, data, 128, 0); + return 1; +} + +int common_hal_i2cperipheral_i2c_peripheral_write_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t data) { + i2c_reset_tx_fifo(self->i2c_num); + i2c_slave_write_buffer(self->i2c_num, &data, 128, 0); + return 1; +} + +void common_hal_i2cperipheral_i2c_peripheral_ack(i2cperipheral_i2c_peripheral_obj_t *self, bool ack) { + +} + +void common_hal_i2cperipheral_i2c_peripheral_close(i2cperipheral_i2c_peripheral_obj_t *self) { + +} diff --git a/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.h b/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.h new file mode 100644 index 0000000000..d3b324b39a --- /dev/null +++ b/ports/espressif/common-hal/i2cperipheral/I2CPeripheral.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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_ESPRESSIF_COMMON_HAL_BUSIO_I2C_PERIPHERAL_H +#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_BUSIO_I2C_PERIPHERAL_H + +#include "py/obj.h" +#include "peripherals/i2c.h" +#include "common-hal/microcontroller/Pin.h" + +typedef struct { + mp_obj_base_t base; + i2c_port_t i2c_num; + uint8_t *addresses; + uint8_t num_addresses; + const mcu_pin_obj_t *scl_pin; + const mcu_pin_obj_t *sda_pin; +} i2cperipheral_i2c_peripheral_obj_t; + +#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_BUSIO_I2C_PERIPHERAL_H diff --git a/ports/espressif/common-hal/i2cperipheral/__init__.c b/ports/espressif/common-hal/i2cperipheral/__init__.c new file mode 100644 index 0000000000..c67511c536 --- /dev/null +++ b/ports/espressif/common-hal/i2cperipheral/__init__.c @@ -0,0 +1 @@ +// No i2cperipheral module functions. diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index bcd08aefe3..a7b69e0933 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -25,7 +25,7 @@ CIRCUITPY_DUALBANK ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_FREQUENCYIO ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 -CIRCUITPY_I2CPERIPHERAL ?= 0 +CIRCUITPY_I2CPERIPHERAL ?= 1 CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_ROTARYIO ?= 1 CIRCUITPY_NVM ?= 1 diff --git a/ports/espressif/peripherals/i2c.c b/ports/espressif/peripherals/i2c.c new file mode 100644 index 0000000000..7a85349f96 --- /dev/null +++ b/ports/espressif/peripherals/i2c.c @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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 "peripherals/i2c.h" + +typedef enum { + STATUS_FREE = 0, + STATUS_IN_USE, + STATUS_NEVER_RESET +} i2c_status_t; + +static i2c_status_t i2c_status[I2C_NUM_MAX]; + +void i2c_reset(void) { + for (i2c_port_t num = 0; num < I2C_NUM_MAX; num++) { + if (i2c_status[num] == STATUS_IN_USE) { + i2c_driver_delete(num); + i2c_status[num] = STATUS_FREE; + } + } +} + +void never_reset_i2c(i2c_port_t num) { + i2c_status[num] = STATUS_NEVER_RESET; +} + +esp_err_t peripherals_i2c_init(i2c_port_t num, const i2c_config_t *i2c_conf) { + esp_err_t err = i2c_param_config(num, i2c_conf); + if (err != ESP_OK) { + return err; + } + size_t rx_buf_len = 0; + size_t tx_buf_len = 0; + if (i2c_conf->mode == I2C_MODE_SLAVE) { + rx_buf_len = 256; + tx_buf_len = 256; + } + return i2c_driver_install(num, i2c_conf->mode, rx_buf_len, tx_buf_len, 0); +} + +void peripherals_i2c_deinit(i2c_port_t num) { + i2c_reset_rx_fifo(num); + i2c_reset_tx_fifo(num); + i2c_driver_delete(num); + i2c_status[num] = STATUS_FREE; +} + +i2c_port_t peripherals_i2c_get_free_num(void) { + i2c_port_t i2c_num = I2C_NUM_MAX; + for (i2c_port_t num = 0; num < I2C_NUM_MAX; num++) { + if (i2c_status[num] == STATUS_FREE) { + i2c_num = num; + break; + } + } + if (i2c_num != I2C_NUM_MAX) { + i2c_status[i2c_num] = STATUS_IN_USE; + } + return i2c_num; +} diff --git a/ports/espressif/peripherals/i2c.h b/ports/espressif/peripherals/i2c.h new file mode 100644 index 0000000000..4e7946d177 --- /dev/null +++ b/ports/espressif/peripherals/i2c.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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_ESPRESSIF_PERIPHERALS_I2C_HANDLER_H +#define MICROPY_INCLUDED_ESPRESSIF_PERIPHERALS_I2C_HANDLER_H + +#include "driver/i2c.h" + +extern void i2c_reset(void); +extern void never_reset_i2c(i2c_port_t num); +extern esp_err_t peripherals_i2c_init(i2c_port_t num, const i2c_config_t *i2c_conf); +extern void peripherals_i2c_deinit(i2c_port_t num); +extern i2c_port_t peripherals_i2c_get_free_num(void); + +#endif // MICROPY_INCLUDED_ESPRESSIF_PERIPHERALS_I2C_HANDLER_H