Skip to content

Commit 5b53914

Browse files
committed
add optional secondary I2C singleton
1 parent fd9c3d1 commit 5b53914

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

py/circuitpy_mpconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ typedef long mp_off_t;
253253

254254
#if CIRCUITPY_BOARD
255255
#define BOARD_I2C (defined(DEFAULT_I2C_BUS_SDA) && defined(DEFAULT_I2C_BUS_SCL))
256+
#define BOARD_SECOND_I2C (defined(SECOND_I2C_BUS_SDA) && defined(SECOND_I2C_BUS_SCL))
256257
#define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI))
257258
#define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX))
258259

shared-bindings/board/__init__.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#include "py/runtime.h"
2929

3030
#include "shared-bindings/board/__init__.h"
31-
#if BOARD_I2C
31+
#if defined(BOARD_I2C) || defined(BOARD_SECOND_I2C)
3232
#include "shared-bindings/busio/I2C.h"
3333
#endif
3434
#if BOARD_SPI
@@ -73,6 +73,30 @@ mp_obj_t board_i2c(void) {
7373
MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c);
7474

7575

76+
//| def SECOND_I2C() -> busio.I2C:
77+
//| """Returns the `busio.I2C` object for the secondary I2C pins, usually the STEMMA[QT] connector. It is a singleton."""
78+
//| ...
79+
//|
80+
81+
#if BOARD_SECOND_I2C
82+
mp_obj_t board_second_i2c(void) {
83+
mp_obj_t singleton = common_hal_board_get_second_i2c();
84+
if (singleton != NULL && !common_hal_busio_i2c_deinited(singleton)) {
85+
return singleton;
86+
}
87+
assert_pin_free(SECOND_I2C_BUS_SDA);
88+
assert_pin_free(SECOND_I2C_BUS_SCL);
89+
return common_hal_board_create_second_i2c();
90+
}
91+
#else
92+
mp_obj_t board_second_i2c(void) {
93+
mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SECOND_I2C);
94+
return NULL;
95+
}
96+
#endif
97+
MP_DEFINE_CONST_FUN_OBJ_0(board_second_i2c_obj, board_second_i2c);
98+
99+
76100
//| def SPI() -> busio.SPI:
77101
//| """Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a
78102
//| singleton."""

shared-bindings/board/__init__.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ mp_obj_t common_hal_board_get_i2c(void);
3939
mp_obj_t common_hal_board_create_i2c(void);
4040
MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj);
4141

42+
mp_obj_t common_hal_board_get_second_i2c(void);
43+
mp_obj_t common_hal_board_create_second_i2c(void);
44+
MP_DECLARE_CONST_FUN_OBJ_0(board_second_i2c_obj);
45+
4246
mp_obj_t common_hal_board_get_spi(void);
4347
mp_obj_t common_hal_board_create_spi(void);
4448
MP_DECLARE_CONST_FUN_OBJ_0(board_spi_obj);

shared-module/board/__init__.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,29 @@ mp_obj_t common_hal_board_create_i2c(void) {
6767
#endif
6868

6969

70+
#if BOARD_SECOND_I2C
71+
// Statically allocate the I2C object so it can live past the end of the heap and into the next VM.
72+
// That way it can be used by built-in I2CDisplay displays and be accessible through board.I2C().
73+
STATIC busio_i2c_obj_t second_i2c_obj;
74+
STATIC mp_obj_t second_i2c_singleton = NULL;
75+
76+
mp_obj_t common_hal_board_get_second_i2c(void) {
77+
return second_i2c_singleton;
78+
}
79+
80+
mp_obj_t common_hal_board_create_second_i2c(void) {
81+
// All callers have either already verified this or come so early that it can't be otherwise.
82+
assert(second_i2c_singleton == NULL || common_hal_busio_i2c_deinited(second_i2c_singleton));
83+
busio_i2c_obj_t *self = &second_i2c_obj;
84+
self->base.type = &busio_i2c_type;
85+
86+
common_hal_busio_i2c_construct(self, SECOND_I2C_BUS_SCL, SECOND_I2C_BUS_SDA, 100000, 255);
87+
second_i2c_singleton = (mp_obj_t)self;
88+
return second_i2c_singleton;
89+
}
90+
#endif
91+
92+
7093
#if BOARD_SPI
7194
// Statically allocate the SPI object so it can live past the end of the heap and into the next VM.
7295
// That way it can be used by built-in FourWire displays and be accessible through board.SPI().
@@ -152,6 +175,23 @@ void reset_board_busses(void) {
152175
}
153176
}
154177
#endif
178+
#if BOARD_SECOND_I2C
179+
bool display_using_second_i2c = false;
180+
#if CIRCUITPY_DISPLAYIO
181+
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
182+
if (displays[i].bus_base.type == &displayio_i2cdisplay_type && displays[i].i2cdisplay_bus.bus == second_i2c_singleton) {
183+
display_using_second_i2c = true;
184+
break;
185+
}
186+
}
187+
#endif
188+
if (second_i2c_singleton != NULL) {
189+
if (!display_using_second_i2c) {
190+
common_hal_busio_i2c_deinit(second_i2c_singleton);
191+
second_i2c_singleton = NULL;
192+
}
193+
}
194+
#endif
155195
#if BOARD_SPI
156196
bool display_using_spi = false;
157197
#if CIRCUITPY_DISPLAYIO

0 commit comments

Comments
 (0)