Skip to content

Commit eff544c

Browse files
committed
espressif: get new I2C driver working
- Starts with @tannewt's changes. - Make sure proper component is being compiled. - Added `I2C.probe()` as a visible new method. This was a hidden common-hal method, but the C version of adafruit_bus_device could not use it because it needs to call probe via a Python method call. So make it visible. It's useful, and `I2C.scan()` could be phased out, since now `.scan()` can be implemented in Python with `.probe()`. - set clock-stretching timeout on espressif to a minimum of 1 second. In all impls of busio.I2C()`, the timeout is ignored and is set to a fixed 1 second. @tannewt's new code was using the passed-in value, which was often too short. To do: - switch esp-camera to new-driver version. We have to use the same I2C driver everywhere. - Check about I2CTarget.
1 parent e9f8ed4 commit eff544c

File tree

9 files changed

+68
-47
lines changed

9 files changed

+68
-47
lines changed

ports/espressif/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16)
55
set(ENV{IDF_PATH} ${CMAKE_SOURCE_DIR}/esp-idf)
66

77
# The component list here determines what options we get in menuconfig and what the ninja file can build.
8-
set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_spi esp_driver_tsens esp_driver_uart esp-tls esp_adc_cal esp_event esp_netif esp_psram esp_wifi esptool_py freertos log lwip main mbedtls mdns soc ulp usb wpa_supplicant esp-camera esp_lcd vfs esp_vfs_console)
8+
set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_spi esp_driver_tsens esp_driver_uart esp-tls esp_adc_cal esp_event esp_netif esp_psram esp_wifi esptool_py freertos log lwip main mbedtls mdns soc ulp usb wpa_supplicant esp-camera esp_lcd vfs esp_vfs_console)
99
set(EXTRA_COMPONENT_DIRS "esp-protocols/components/mdns" "esp-camera")
1010

1111
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

ports/espressif/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ INC += \
6565
-isystem esp-idf/components/bt/host/nimble/nimble/porting/nimble/include \
6666
-isystem esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/include \
6767
-isystem esp-idf/components/bt/host/nimble/port/include \
68-
-isystem esp-idf/components/driver/i2c/include \
6968
-isystem esp-idf/components/driver/touch_sensor/include \
7069
-isystem esp-idf/components/driver/touch_sensor/$(IDF_TARGET)/include \
7170
-isystem esp-idf/components/driver/twai/include \
@@ -613,7 +612,7 @@ ifeq ($(IDF_TARGET),esp32)
613612
BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/librtc.a
614613
endif
615614

616-
ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console
615+
ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console
617616
ifneq ($(CIRCUITPY_WIFI),0)
618617
ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy
619618
endif

ports/espressif/common-hal/busio/I2C.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,15 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
9393
self->scl_pin = scl;
9494
self->has_lock = false;
9595
self->frequency = frequency;
96-
self->timeout_ms = timeout_us / 1000;
97-
// Round up timeout to nearest ms.
98-
if (timeout_us % 1000 != 0) {
99-
self->timeout_ms += 1;
100-
}
96+
97+
// Ignore the passed-in clock-stretching timeout. It is not used, as documented in shared-bindings.
98+
// Instead use 1000 ms, which is standard across ports.
99+
// self->timeout_ms = timeout_us / 1000;
100+
// // Round up timeout to nearest ms.
101+
// if (timeout_us % 1000 != 0) {
102+
// self->timeout_ms += 1;
103+
// }
104+
self->timeout_ms = 1000;
101105

102106
claim_pin(sda);
103107
claim_pin(scl);
@@ -164,11 +168,11 @@ static uint8_t convert_esp_err(esp_err_t result) {
164168
}
165169
}
166170

167-
static size_t _transaction_duration(size_t frequency, size_t len) {
171+
static size_t _transaction_duration_ms(size_t frequency, size_t len) {
168172
size_t khz = frequency / 1000;
169173
size_t bytes_per_ms = khz / 8;
170174
// + 1 for the address byte
171-
return (len + 1) / bytes_per_ms;
175+
return (len + 1) / bytes_per_ms + 1000;
172176
}
173177

174178
uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) {
@@ -179,7 +183,7 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const u
179183
};
180184
i2c_master_dev_handle_t dev_handle;
181185
CHECK_ESP_RESULT(i2c_master_bus_add_device(self->handle, &dev_config, &dev_handle));
182-
esp_err_t result = i2c_master_transmit(dev_handle, data, len, _transaction_duration(self->frequency, len) + self->timeout_ms);
186+
esp_err_t result = i2c_master_transmit(dev_handle, data, len, _transaction_duration_ms(self->frequency, len) + self->timeout_ms);
183187
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
184188
return convert_esp_err(result);
185189
}
@@ -192,7 +196,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t
192196
};
193197
i2c_master_dev_handle_t dev_handle;
194198
CHECK_ESP_RESULT(i2c_master_bus_add_device(self->handle, &dev_config, &dev_handle));
195-
esp_err_t result = i2c_master_receive(dev_handle, data, len, _transaction_duration(self->frequency, len) + self->timeout_ms);
199+
esp_err_t result = i2c_master_receive(dev_handle, data, len, _transaction_duration_ms(self->frequency, len) + self->timeout_ms);
196200
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
197201
return convert_esp_err(result);
198202
}
@@ -206,7 +210,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr,
206210
};
207211
i2c_master_dev_handle_t dev_handle;
208212
CHECK_ESP_RESULT(i2c_master_bus_add_device(self->handle, &dev_config, &dev_handle));
209-
esp_err_t result = i2c_master_transmit_receive(dev_handle, out_data, out_len, in_data, in_len, _transaction_duration(self->frequency, out_len) + _transaction_duration(self->frequency, in_len) + self->timeout_ms);
213+
esp_err_t result = i2c_master_transmit_receive(dev_handle, out_data, out_len, in_data, in_len, _transaction_duration_ms(self->frequency, out_len) + _transaction_duration_ms(self->frequency, in_len) + self->timeout_ms);
210214
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
211215
return convert_esp_err(result);
212216
}

ports/espressif/mpconfigport.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ CIRCUITPY_BLEIO ?= 1
3737
CIRCUITPY_BLEIO_HCI = 0
3838
CIRCUITPY_CANIO ?= 1
3939
CIRCUITPY_COUNTIO ?= 1
40-
CIRCUITPY_ESPCAMERA ?= 1
40+
############ TEMPORARY while working on new I2C driver
41+
CIRCUITPY_ESPCAMERA ?= 0
4142
CIRCUITPY_ESPIDF ?= 1
4243
CIRCUITPY_ESPULP ?= 1
4344
CIRCUITPY_FRAMEBUFFERIO ?= 1

ports/silabs/common-hal/busio/I2C.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
#include "shared-bindings/microcontroller/__init__.h"
3131
#include "shared-bindings/microcontroller/Pin.h"
3232

33-
STATIC I2CSPM_Init_TypeDef i2cspm_init;
34-
STATIC bool in_used = false;
33+
static I2CSPM_Init_TypeDef i2cspm_init;
34+
static bool in_used = false;
3535

3636
// Construct I2C protocol, this function init i2c peripheral
3737
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,

ports/stm/common-hal/busio/I2C.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
// Arrays use 0 based numbering: I2C1 is stored at index 0
4141
#define MAX_I2C 4
4242

43-
STATIC bool reserved_i2c[MAX_I2C];
43+
static bool reserved_i2c[MAX_I2C];
4444

4545
#define ALL_CLOCKS 0xFF
4646
static void i2c_clock_enable(uint8_t mask);

shared-bindings/bitbangio/I2C.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ static mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
5959
const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj, MP_QSTR_scl);
6060
const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj, MP_QSTR_sda);
6161

62-
bitbangio_i2c_obj_t *self = m_new_obj_with_finaliser(bitbangio_i2c_obj_t);
63-
self->base.type = &bitbangio_i2c_type;
62+
bitbangio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(bitbangio_i2c_obj_t, &bitbangio_i2c_type);
6463
shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
6564
return (mp_obj_t)self;
6665
}
@@ -103,6 +102,23 @@ static void check_lock(bitbangio_i2c_obj_t *self) {
103102
}
104103
}
105104

105+
//| def probe(self, address: int) -> List[int]:
106+
//| """Check if a device at the specified address responds.
107+
//|
108+
//| :param int address: 7-bit device address
109+
//| :return: ``True`` if a device at ``address`` responds; ``False`` otherwise
110+
//| :rtype: bool"""
111+
//| ...
112+
static mp_obj_t bitbangio_i2c_probe(mp_obj_t self_in, mp_obj_t address_obj) {
113+
bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
114+
check_for_deinit(self);
115+
check_lock(self);
116+
117+
const uint16_t addr = mp_obj_get_int(address_obj);
118+
return mp_obj_new_bool(shared_module_bitbangio_i2c_probe(self, addr));
119+
}
120+
MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_i2c_probe_obj, bitbangio_i2c_probe);
121+
106122
//| def scan(self) -> List[int]:
107123
//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
108124
//| those that respond. A device responds if it pulls the SDA line low after
@@ -331,6 +347,7 @@ static const mp_rom_map_elem_t bitbangio_i2c_locals_dict_table[] = {
331347
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bitbangio_i2c_deinit_obj) },
332348
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
333349
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bitbangio_i2c_obj___exit___obj) },
350+
{ MP_ROM_QSTR(MP_QSTR_probe), MP_ROM_PTR(&bitbangio_i2c_probe_obj) },
334351
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bitbangio_i2c_scan_obj) },
335352

336353
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&bitbangio_i2c_try_lock_obj) },

shared-bindings/busio/I2C.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
//| ...
4949
static mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
5050
#if CIRCUITPY_BUSIO_I2C
51-
busio_i2c_obj_t *self = mp_obj_malloc(busio_i2c_obj_t, &busio_i2c_type);
5251
enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout };
5352
static const mp_arg_t allowed_args[] = {
5453
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
@@ -62,8 +61,7 @@ static mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz
6261
const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj, MP_QSTR_scl);
6362
const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj, MP_QSTR_sda);
6463

65-
busio_i2c_obj_t *self = m_new_obj_with_finaliser(busio_i2c_obj_t);
66-
self->base.type = &busio_i2c_type;
64+
busio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(busio_i2c_obj_t, &busio_i2c_type);
6765
common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
6866
return (mp_obj_t)self;
6967
#else
@@ -98,12 +96,12 @@ static void check_for_deinit(busio_i2c_obj_t *self) {
9896
//| """Automatically deinitializes the hardware on context exit. See
9997
//| :ref:`lifetime-and-contextmanagers` for more info."""
10098
//| ...
101-
STATIC mp_obj_t busio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) {
99+
static mp_obj_t busio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) {
102100
(void)n_args;
103101
common_hal_busio_i2c_deinit(MP_OBJ_TO_PTR(args[0]));
104102
return mp_const_none;
105103
}
106-
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i2c_obj___exit__);
104+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i2c_obj___exit__);
107105

108106
static void check_lock(busio_i2c_obj_t *self) {
109107
asm ("");
@@ -112,6 +110,23 @@ static void check_lock(busio_i2c_obj_t *self) {
112110
}
113111
}
114112

113+
//| def probe(self, address: int) -> List[int]:
114+
//| """Check if a device at the specified address responds.
115+
//|
116+
//| :param int address: 7-bit device address
117+
//| :return: ``True`` if a device at ``address`` responds; ``False`` otherwise
118+
//| :rtype: bool"""
119+
//| ...
120+
static mp_obj_t busio_i2c_probe(mp_obj_t self_in, mp_obj_t address_obj) {
121+
busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
122+
check_for_deinit(self);
123+
check_lock(self);
124+
125+
const uint16_t addr = mp_obj_get_int(address_obj);
126+
return mp_obj_new_bool(common_hal_busio_i2c_probe(self, addr));
127+
}
128+
MP_DEFINE_CONST_FUN_OBJ_2(busio_i2c_probe_obj, busio_i2c_probe);
129+
115130
//| def scan(self) -> List[int]:
116131
//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a
117132
//| list of those that respond.
@@ -366,6 +381,7 @@ static const mp_rom_map_elem_t busio_i2c_locals_dict_table[] = {
366381
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_i2c_deinit_obj) },
367382
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
368383
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_i2c___exit___obj) },
384+
{ MP_ROM_QSTR(MP_QSTR_probe), MP_ROM_PTR(&busio_i2c_probe_obj) },
369385
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&busio_i2c_scan_obj) },
370386

371387
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&busio_i2c_try_lock_obj) },

shared-module/adafruit_bus_device/i2c_device/I2CDevice.c

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,14 @@ void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevi
4141
void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self) {
4242
common_hal_adafruit_bus_device_i2cdevice_lock(self);
4343

44-
mp_buffer_info_t write_bufinfo;
45-
mp_obj_t write_buffer = mp_obj_new_bytearray_of_zeros(0);
46-
mp_get_buffer_raise(write_buffer, &write_bufinfo, MP_BUFFER_READ);
44+
mp_obj_t dest[3];
45+
mp_load_method(self->i2c, MP_QSTR_probe, dest);
46+
dest[2] = MP_OBJ_NEW_SMALL_INT(self->device_address);
47+
const bool found = mp_obj_is_true(mp_call_method_n_kw(1, 0, dest));
4748

48-
mp_obj_t dest[4];
49-
50-
/* catch exceptions that may be thrown while probing for the device */
51-
nlr_buf_t nlr;
52-
if (nlr_push(&nlr) == 0) {
53-
mp_load_method(self->i2c, MP_QSTR_writeto, dest);
54-
dest[2] = MP_OBJ_NEW_SMALL_INT(self->device_address);
55-
dest[3] = write_buffer;
56-
mp_call_method_n_kw(2, 0, dest);
57-
nlr_pop();
58-
} else {
59-
common_hal_adafruit_bus_device_i2cdevice_unlock(self);
49+
common_hal_adafruit_bus_device_i2cdevice_unlock(self);
6050

61-
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
62-
mp_raise_ValueError_varg(MP_ERROR_TEXT("No I2C device at address: 0x%x"), self->device_address);
63-
} else {
64-
/* In case we receive an unrelated exception pass it up */
65-
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
66-
}
51+
if (!found) {
52+
mp_raise_ValueError_varg(MP_ERROR_TEXT("No I2C device at address: 0x%x"), self->device_address);
6753
}
68-
69-
common_hal_adafruit_bus_device_i2cdevice_unlock(self);
7054
}

0 commit comments

Comments
 (0)