Skip to content

Commit e9f8ed4

Browse files
tannewtdhalbert
authored andcommitted
Switch to IDF 5.2 I2C API
Make busio.I2C use finalizers for reset instead of bulk reset. This makes it easier to track and free the memory that the IDF allocates internally for its "handle".
1 parent 13d659a commit e9f8ed4

File tree

31 files changed

+169
-292
lines changed

31 files changed

+169
-292
lines changed

ports/atmel-samd/common-hal/busio/I2C.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,29 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
108108
mp_arg_error_invalid(MP_QSTR_frequency);
109109
}
110110

111-
self->sda_pin = sda->number;
112-
self->scl_pin = scl->number;
113-
claim_pin(sda);
114-
claim_pin(scl);
115111

116112
if (i2c_m_sync_enable(&self->i2c_desc) != ERR_NONE) {
117113
common_hal_busio_i2c_deinit(self);
118114
mp_raise_OSError(MP_EIO);
119115
}
116+
117+
self->sda_pin = sda->number;
118+
self->scl_pin = scl->number;
119+
claim_pin(sda);
120+
claim_pin(scl);
121+
122+
// Prevent bulk sercom reset from resetting us. The finalizer will instead.
123+
never_reset_sercom(self->i2c_desc.device.hw);
120124
}
121125

122126
bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
123127
return self->sda_pin == NO_PIN;
124128
}
125129

130+
void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) {
131+
self->sda_pin = NO_PIN;
132+
}
133+
126134
void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
127135
if (common_hal_busio_i2c_deinited(self)) {
128136
return;
@@ -135,6 +143,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
135143
reset_pin_number(self->scl_pin);
136144
self->sda_pin = NO_PIN;
137145
self->scl_pin = NO_PIN;
146+
common_hal_busio_i2c_mark_deinit(self);
138147
}
139148

140149
bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
@@ -236,8 +245,6 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr,
236245
}
237246

238247
void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) {
239-
never_reset_sercom(self->i2c_desc.device.hw);
240-
241248
never_reset_pin_number(self->scl_pin);
242249
never_reset_pin_number(self->sda_pin);
243250
}

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

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,8 @@ static BSC0_Type *i2c[NUM_I2C] = {BSC0, BSC1, NULL, BSC3, BSC4, BSC5, BSC6, NULL
2323
static BSC0_Type *i2c[NUM_I2C] = {BSC0, BSC1, NULL};
2424
#endif
2525

26-
static bool never_reset_i2c[NUM_I2C];
2726
static bool i2c_in_use[NUM_I2C];
2827

29-
void reset_i2c(void) {
30-
// BSC2 is dedicated to the first HDMI output.
31-
never_reset_i2c[2] = true;
32-
i2c_in_use[2] = true;
33-
#if BCM_VERSION == 2711
34-
// BSC7 is dedicated to the second HDMI output.
35-
never_reset_i2c[7] = true;
36-
i2c_in_use[7] = true;
37-
#endif
38-
for (size_t i = 0; i < NUM_I2C; i++) {
39-
if (never_reset_i2c[i]) {
40-
continue;
41-
}
42-
i2c_in_use[i] = false;
43-
i2c[i]->C_b.I2CEN = false;
44-
COMPLETE_MEMORY_READS;
45-
}
46-
}
47-
4828
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
4929
const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) {
5030
size_t instance_index = NUM_I2C;
@@ -90,17 +70,21 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
9070
return self->sda_pin == NULL;
9171
}
9272

73+
void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) {
74+
self->sda_pin = NULL;
75+
}
76+
9377
void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
9478
if (common_hal_busio_i2c_deinited(self)) {
9579
return;
9680
}
97-
never_reset_i2c[self->index] = false;
9881
i2c_in_use[self->index] = false;
9982

10083
common_hal_reset_pin(self->sda_pin);
10184
common_hal_reset_pin(self->scl_pin);
10285
self->sda_pin = NULL;
10386
self->scl_pin = NULL;
87+
common_hal_busio_i2c_mark_deinit(self);
10488
}
10589

10690
bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
@@ -246,8 +230,6 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr,
246230
}
247231

248232
void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) {
249-
never_reset_i2c[self->index] = true;
250-
251233
common_hal_never_reset_pin(self->scl_pin);
252234
common_hal_never_reset_pin(self->sda_pin);
253235
}

ports/broadcom/common-hal/busio/I2C.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,3 @@ typedef struct {
2323
bool finish_write;
2424
uint8_t last_write_data;
2525
} busio_i2c_obj_t;
26-
27-
void reset_i2c(void);

ports/broadcom/supervisor/port.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "genhdr/mpversion.h"
1414

1515
#include "common-hal/rtc/RTC.h"
16-
#include "common-hal/busio/I2C.h"
1716
#include "common-hal/busio/SPI.h"
1817
#include "common-hal/busio/UART.h"
1918

@@ -66,7 +65,6 @@ safe_mode_t port_init(void) {
6665

6766
void reset_port(void) {
6867
#if CIRCUITPY_BUSIO
69-
reset_i2c();
7068
reset_spi();
7169
reset_uart();
7270
#endif

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,18 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
4444

4545
reset_pin_number(self->scl_pin->number);
4646
reset_pin_number(self->sda_pin->number);
47+
48+
common_hal_busio_i2c_mark_deinit(self);
4749
}
4850

4951
bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
5052
return self->i2c_dev == NULL;
5153
}
5254

55+
void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) {
56+
self->i2c_dev = NULL;
57+
}
58+
5359
bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) {
5460
if (common_hal_busio_i2c_deinited(self)) {
5561
return false;

ports/espressif/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ SRC_C += \
392392
boards/$(BOARD)/board.c \
393393
boards/$(BOARD)/pins.c \
394394
shared/netutils/netutils.c \
395-
peripherals/i2c.c \
396395
peripherals/$(IDF_TARGET)/pins.c
397396

398397
ifeq ($(CIRCUITPY_SSL),1)

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

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010

1111
#include "components/driver/i2c/include/driver/i2c.h"
1212

13+
#include "bindings/espidf/__init__.h"
1314
#include "shared-bindings/microcontroller/__init__.h"
1415
#include "shared-bindings/microcontroller/Pin.h"
1516

1617
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
17-
const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) {
18+
const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout_us) {
1819
// Pins 45 and 46 are "strapping" pins that impact start up behavior. They usually need to
1920
// be pulled-down so pulling them up for I2C is a bad idea. To make this hard, we don't
2021
// support I2C on these pins.
@@ -60,44 +61,42 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
6061
}
6162
#endif
6263

64+
65+
i2c_master_bus_config_t config = {
66+
.i2c_port = -1, // auto
67+
.sda_io_num = sda->number,
68+
.scl_io_num = scl->number,
69+
.clk_source = I2C_CLK_SRC_DEFAULT,
70+
.glitch_ignore_cnt = 7,
71+
.flags = {
72+
#if CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP
73+
.enable_internal_pullup = true, /*!< Internal GPIO pull mode for I2C sda signal*/
74+
#else
75+
.enable_internal_pullup = false, /*!< Internal GPIO pull mode for I2C sda signal*/
76+
#endif
77+
}
78+
};
79+
esp_err_t result = i2c_new_master_bus(&config, &self->handle);
80+
81+
if (result == ESP_ERR_NOT_FOUND) {
82+
mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use"));
83+
}
84+
CHECK_ESP_RESULT(result);
85+
6386
self->xSemaphore = xSemaphoreCreateMutex();
6487
if (self->xSemaphore == NULL) {
88+
i2c_del_master_bus(self->handle);
89+
self->handle = NULL;
6590
mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock"));
6691
}
6792
self->sda_pin = sda;
6893
self->scl_pin = scl;
69-
self->i2c_num = peripherals_i2c_get_free_num();
70-
self->has_lock = 0;
71-
72-
if (self->i2c_num == I2C_NUM_MAX) {
73-
mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use"));
74-
}
75-
76-
const i2c_config_t i2c_conf = {
77-
.mode = I2C_MODE_MASTER,
78-
.sda_io_num = self->sda_pin->number,
79-
.scl_io_num = self->scl_pin->number,
80-
#if CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP
81-
.sda_pullup_en = GPIO_PULLUP_ENABLE, /*!< Internal GPIO pull mode for I2C sda signal*/
82-
.scl_pullup_en = GPIO_PULLUP_ENABLE, /*!< Internal GPIO pull mode for I2C scl signal*/
83-
#else
84-
.sda_pullup_en = GPIO_PULLUP_DISABLE, /*!< Internal GPIO pull mode for I2C sda signal*/
85-
.scl_pullup_en = GPIO_PULLUP_DISABLE, /*!< Internal GPIO pull mode for I2C scl signal*/
86-
#endif
87-
88-
.master = {
89-
.clk_speed = frequency,
90-
}
91-
};
92-
93-
// Initialize I2C.
94-
esp_err_t err = peripherals_i2c_init(self->i2c_num, &i2c_conf);
95-
if (err != ESP_OK) {
96-
if (err == ESP_FAIL) {
97-
mp_raise_OSError(MP_EIO);
98-
} else {
99-
mp_raise_RuntimeError(MP_ERROR_TEXT("init I2C"));
100-
}
94+
self->has_lock = false;
95+
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;
101100
}
102101

103102
claim_pin(sda);
@@ -108,32 +107,27 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
108107
return self->sda_pin == NULL;
109108
}
110109

110+
void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) {
111+
self->sda_pin = NULL;
112+
}
113+
111114
void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
112115
if (common_hal_busio_i2c_deinited(self)) {
113116
return;
114117
}
115118

116-
peripherals_i2c_deinit(self->i2c_num);
119+
i2c_del_master_bus(self->handle);
120+
self->handle = NULL;
117121

118122
common_hal_reset_pin(self->sda_pin);
119123
common_hal_reset_pin(self->scl_pin);
120124
self->sda_pin = NULL;
121125
self->scl_pin = NULL;
122-
}
123-
124-
static esp_err_t i2c_zero_length_write(busio_i2c_obj_t *self, uint8_t addr, TickType_t timeout) {
125-
// i2c_master_write_to_device() won't do zero-length writes, so we do it by hand.
126-
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
127-
i2c_master_start(cmd);
128-
i2c_master_write_byte(cmd, addr << 1, true);
129-
i2c_master_stop(cmd);
130-
esp_err_t result = i2c_master_cmd_begin(self->i2c_num, cmd, timeout);
131-
i2c_cmd_link_delete(cmd);
132-
return result;
126+
common_hal_busio_i2c_mark_deinit(self);
133127
}
134128

135129
bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
136-
esp_err_t result = i2c_zero_length_write(self, addr, pdMS_TO_TICKS(10));
130+
esp_err_t result = i2c_master_probe(self->handle, addr, 1);
137131
return result == ESP_OK;
138132
}
139133

@@ -170,28 +164,54 @@ static uint8_t convert_esp_err(esp_err_t result) {
170164
}
171165
}
172166

167+
static size_t _transaction_duration(size_t frequency, size_t len) {
168+
size_t khz = frequency / 1000;
169+
size_t bytes_per_ms = khz / 8;
170+
// + 1 for the address byte
171+
return (len + 1) / bytes_per_ms;
172+
}
173+
173174
uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) {
174-
return convert_esp_err(len == 0
175-
? i2c_zero_length_write(self, addr, pdMS_TO_TICKS(1000))
176-
: i2c_master_write_to_device(self->i2c_num, (uint8_t)addr, data, len, pdMS_TO_TICKS(1000))
177-
);
175+
i2c_device_config_t dev_config = {
176+
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
177+
.device_address = addr,
178+
.scl_speed_hz = self->frequency
179+
};
180+
i2c_master_dev_handle_t dev_handle;
181+
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);
183+
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
184+
return convert_esp_err(result);
178185
}
179186

180187
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) {
181-
return convert_esp_err(
182-
i2c_master_read_from_device(self->i2c_num, (uint8_t)addr, data, len, pdMS_TO_TICKS(1000)));
188+
i2c_device_config_t dev_config = {
189+
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
190+
.device_address = addr,
191+
.scl_speed_hz = self->frequency
192+
};
193+
i2c_master_dev_handle_t dev_handle;
194+
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);
196+
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
197+
return convert_esp_err(result);
183198
}
184199

185200
uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr,
186201
uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) {
187-
return convert_esp_err(
188-
i2c_master_write_read_device(self->i2c_num, (uint8_t)addr,
189-
out_data, out_len, in_data, in_len, pdMS_TO_TICKS(1000)));
202+
i2c_device_config_t dev_config = {
203+
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
204+
.device_address = addr,
205+
.scl_speed_hz = self->frequency
206+
};
207+
i2c_master_dev_handle_t dev_handle;
208+
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);
210+
CHECK_ESP_RESULT(i2c_master_bus_rm_device(dev_handle));
211+
return convert_esp_err(result);
190212
}
191213

192214
void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) {
193-
never_reset_i2c(self->i2c_num);
194-
195215
common_hal_never_reset_pin(self->scl_pin);
196216
common_hal_never_reset_pin(self->sda_pin);
197217
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
#include "freertos/semphr.h"
1414
#include "py/obj.h"
1515

16-
#include "peripherals/i2c.h"
16+
#include "driver/i2c_master.h"
1717

1818
typedef struct {
1919
mp_obj_base_t base;
2020
const mcu_pin_obj_t *scl_pin;
2121
const mcu_pin_obj_t *sda_pin;
22-
i2c_port_t i2c_num;
22+
size_t timeout_ms;
23+
size_t frequency;
24+
i2c_master_bus_handle_t handle;
2325
SemaphoreHandle_t xSemaphore;
2426
bool has_lock;
2527
} busio_i2c_obj_t;

0 commit comments

Comments
 (0)