Skip to content

Commit 927a720

Browse files
committed
Fix I2C and feedback from Dan
1 parent a1052d5 commit 927a720

File tree

24 files changed

+346
-49
lines changed

24 files changed

+346
-49
lines changed

ports/broadcom/bindings/videocore/Framebuffer.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,9 @@ STATIC mp_obj_t videocore_framebuffer_make_new(const mp_obj_type_t *type, size_t
6060
videocore_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->videocore;
6161
self->base.type = &videocore_framebuffer_type;
6262

63-
if (args[ARG_width].u_int <= 0) {
64-
mp_raise_ValueError(translate("width must be greater than zero"));
65-
}
66-
67-
common_hal_videocore_framebuffer_construct(self,
68-
args[ARG_width].u_int,
69-
args[ARG_height].u_int);
63+
mp_uint_t width = (mp_uint_t)mp_arg_validate_int_min(args[ARG_width].u_int, 0, MP_QSTR_width);
64+
mp_uint_t height = (mp_uint_t)mp_arg_validate_int_min(args[ARG_height].u_int, 0, MP_QSTR_height);
65+
common_hal_videocore_framebuffer_construct(self, width, height);
7066

7167
return MP_OBJ_FROM_PTR(self);
7268
}
@@ -136,7 +132,7 @@ STATIC void videocore_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t
136132
common_hal_videocore_framebuffer_get_buffer(self_in, bufinfo, 0);
137133
}
138134

139-
// These version exists so that the prototype matches the protocol,
135+
// These versions exist so that the prototype matches the protocol,
140136
// avoiding a type cast that can hide errors
141137
STATIC void videocore_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
142138
(void)dirty_row_bitmap;

ports/broadcom/bindings/videocore/Framebuffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
extern const mp_obj_type_t videocore_framebuffer_type;
3232

33-
void common_hal_videocore_framebuffer_construct(videocore_framebuffer_obj_t *self, uint16_t width, uint16_t height);
33+
void common_hal_videocore_framebuffer_construct(videocore_framebuffer_obj_t *self, mp_uint_t width, mp_uint_t height);
3434
void common_hal_videocore_framebuffer_deinit(videocore_framebuffer_obj_t *self);
3535
bool common_hal_videocore_framebuffer_deinited(videocore_framebuffer_obj_t *self);
3636
void common_hal_videocore_framebuffer_refresh(videocore_framebuffer_obj_t *self);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Compute Module 4 IO Board"
2+
3+
#define DEFAULT_I2C_BUS_SCL (&pin_GPIO3)
4+
#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2)

ports/broadcom/boards/raspberrypi_cm4io/pins.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
5757
{ MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) },
5858
{ MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_GPIO27) },
5959

60+
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
6061
{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)},
6162
};
6263
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
#define MICROPY_HW_BOARD_NAME "Raspberry Pi 4B"
2+
3+
#define DEFAULT_I2C_BUS_SCL (&pin_GPIO3)
4+
#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2)

ports/broadcom/boards/raspberrypi_pi4b/pins.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
5757
{ MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) },
5858
{ MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_GPIO27) },
5959

60+
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
6061
{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)},
6162
};
6263
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Zero 2W"
2+
3+
#define DEFAULT_I2C_BUS_SCL (&pin_GPIO3)
4+
#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2)

ports/broadcom/boards/raspberrypi_zero2w/pins.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,59 @@
22

33
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
44
CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
5+
// These match the names used in Blinka
6+
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) },
7+
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) },
58

6-
{ MP_ROM_QSTR(MP_QSTR_GPIO18), MP_ROM_PTR(&pin_GPIO18) },
7-
{ MP_ROM_QSTR(MP_QSTR_GPIO19), MP_ROM_PTR(&pin_GPIO19) },
8-
{ MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) },
9-
{ MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) },
9+
{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) },
10+
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) },
11+
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) },
12+
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) },
13+
14+
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) },
15+
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) },
16+
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
17+
18+
{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) },
19+
{ MP_ROM_QSTR(MP_QSTR_CE1), MP_ROM_PTR(&pin_GPIO7) },
20+
{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) },
21+
{ MP_ROM_QSTR(MP_QSTR_CE0), MP_ROM_PTR(&pin_GPIO8) },
22+
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) },
23+
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO9) },
24+
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) },
25+
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) },
26+
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) },
27+
{ MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO11) },
28+
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO11) },
29+
30+
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) },
31+
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) },
32+
33+
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) },
34+
{ MP_ROM_QSTR(MP_QSTR_TXD), MP_ROM_PTR(&pin_GPIO14) },
35+
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) },
36+
{ MP_ROM_QSTR(MP_QSTR_RXD), MP_ROM_PTR(&pin_GPIO15) },
37+
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO14) },
38+
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO15) },
39+
40+
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) },
41+
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) },
42+
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) },
43+
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) },
44+
{ MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO19) },
45+
{ MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) },
46+
{ MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO20) },
47+
{ MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) },
48+
{ MP_ROM_QSTR(MP_QSTR_SCLK_1), MP_ROM_PTR(&pin_GPIO21) },
49+
{ MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO21) },
50+
{ MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) },
51+
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) },
52+
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) },
53+
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) },
54+
{ MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) },
55+
{ MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_GPIO27) },
56+
57+
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
58+
{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)},
1059
};
1160
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

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

Lines changed: 136 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,46 +30,73 @@
3030
#include "py/runtime.h"
3131

3232
#include "shared-bindings/microcontroller/__init__.h"
33+
#include "shared-bindings/microcontroller/Pin.h"
3334

34-
#define NO_PIN 0xff
35+
#include "peripherals/broadcom/cpu.h"
36+
#include "peripherals/broadcom/vcmailbox.h"
3537

36-
// One second
37-
#define BUS_TIMEOUT_US 1000000
38+
#define NUM_I2C (2)
3839

39-
STATIC bool never_reset_i2c[2];
40-
// STATIC i2c_inst_t *i2c[2] = {i2c0, i2c1};
40+
STATIC bool never_reset_i2c[NUM_I2C];
41+
STATIC bool in_use_i2c[NUM_I2C];
42+
STATIC BSC0_Type *i2c[2] = {BSC0, BSC1};
4143

4244
void reset_i2c(void) {
4345
for (size_t i = 0; i < 2; i++) {
4446
if (never_reset_i2c[i]) {
4547
continue;
4648
}
47-
49+
in_use_i2c[i] = false;
4850
}
4951
}
5052

5153
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
5254
const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) {
55+
size_t instance_index = NUM_I2C;
56+
if ((scl == &pin_GPIO1 || scl == &pin_GPIO29 || scl == &pin_GPIO45) &&
57+
(sda == &pin_GPIO0 || sda == &pin_GPIO28 || sda == &pin_GPIO44)) {
58+
instance_index = 0;
59+
} else if ((scl == &pin_GPIO44 || scl == &pin_GPIO3) &&
60+
(sda == &pin_GPIO43 || sda == &pin_GPIO2)) {
61+
instance_index = 1;
62+
}
63+
if (instance_index == NUM_I2C) {
64+
mp_raise_ValueError(translate("Invalid pins"));
65+
}
66+
in_use_i2c[instance_index] = true;
67+
self->index = instance_index;
68+
self->peripheral = i2c[self->index];
69+
self->sda_pin = sda;
70+
self->scl_pin = scl;
71+
72+
uint32_t source_clock = vcmailbox_get_clock_rate_measured(VCMAILBOX_CLOCK_CORE);
73+
uint16_t clock_divider = source_clock / frequency;
74+
self->peripheral->DIV_b.CDIV = clock_divider;
75+
76+
gpio_set_function(sda->number, GPIO_GPFSEL0_FSEL2_SDA1);
77+
gpio_set_function(scl->number, GPIO_GPFSEL0_FSEL3_SCL1);
5378
}
5479

5580
bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
56-
return self->sda_pin == NO_PIN;
81+
return self->sda_pin == NULL;
5782
}
5883

5984
void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
6085
if (common_hal_busio_i2c_deinited(self)) {
6186
return;
6287
}
63-
// never_reset_i2c[i2c_hw_index(self->peripheral)] = false;
88+
never_reset_i2c[self->index] = false;
6489

65-
reset_pin_number(self->sda_pin);
66-
reset_pin_number(self->scl_pin);
67-
self->sda_pin = NO_PIN;
68-
self->scl_pin = NO_PIN;
90+
common_hal_reset_pin(self->sda_pin);
91+
common_hal_reset_pin(self->scl_pin);
92+
self->sda_pin = NULL;
93+
self->scl_pin = NULL;
6994
}
7095

7196
bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
72-
return common_hal_busio_i2c_write(self, addr, NULL, 0, true) == 0;
97+
uint8_t result = common_hal_busio_i2c_write(self, addr, NULL, 0, true);
98+
// mp_printf(&mp_plat_print, "result %d %d\n", addr, result);
99+
return result == 0;
73100
}
74101

75102
bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) {
@@ -89,20 +116,111 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) {
89116
self->has_lock = false;
90117
}
91118

119+
// Discussion of I2C implementation is here: https://github.com/raspberrypi/linux/issues/254
120+
92121
uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr,
93122
const uint8_t *data, size_t len, bool transmit_stop_bit) {
123+
COMPLETE_MEMORY_READS;
124+
self->peripheral->S_b.DONE = true;
125+
self->peripheral->A_b.ADDR = addr;
126+
size_t loop_len = len;
127+
// Prevent the stop bit by transmitting everything but the last byte. Doing
128+
// so is left up to the subsequent read.
129+
if (!transmit_stop_bit) {
130+
loop_len -= 1;
131+
}
132+
self->peripheral->DLEN_b.DLEN = len;
133+
self->peripheral->C = BSC0_C_ST_Msk | BSC0_C_I2CEN_Msk;
134+
// Wait for the transaction to start.
135+
while (self->peripheral->S_b.TA == 0) {
136+
RUN_BACKGROUND_TASKS;
137+
}
138+
for (size_t i = 0; i < loop_len; i++) {
139+
if (self->peripheral->S_b.ERR) {
140+
break;
141+
}
142+
self->peripheral->FIFO_b.DATA = data[i];
143+
// Wait for the FIFO to empty enough that we can write more data.
144+
while (self->peripheral->S_b.TXE == 0) {
145+
RUN_BACKGROUND_TASKS;
146+
}
147+
}
148+
// Wait for the FIFO to empty completely, not DONE, because we may not complete the
149+
// transaction with a write.
150+
while (self->peripheral->S_b.ERR == 0 &&
151+
((!transmit_stop_bit && self->peripheral->S_b.TXE == 0) ||
152+
(transmit_stop_bit && self->peripheral->S_b.TA == 1))) {
153+
RUN_BACKGROUND_TASKS;
154+
}
155+
self->finish_write = false;
156+
if (self->peripheral->S_b.ERR) {
157+
// Wait for the transfer to finish.
158+
while (self->peripheral->S_b.TA == 1) {
159+
RUN_BACKGROUND_TASKS;
160+
}
161+
// Clear the flag by writing it and wait for it to clear.
162+
self->peripheral->S_b.ERR = true;
163+
while (self->peripheral->S_b.ERR == 1) {
164+
RUN_BACKGROUND_TASKS;
165+
}
166+
return MP_ENODEV;
167+
}
94168

95-
return MP_ENODEV;
169+
if (loop_len < len) {
170+
self->finish_write = true;
171+
self->last_write_data = data[len - 1];
172+
}
173+
return 0;
96174
}
97175

98176
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr,
99177
uint8_t *data, size_t len) {
100-
return MP_ENODEV;
178+
COMPLETE_MEMORY_READS;
179+
self->peripheral->A_b.ADDR = addr;
180+
if (self->finish_write) {
181+
self->finish_write = false;
182+
if (self->peripheral->S_b.ERR == 1) {
183+
return MP_ENODEV;
184+
}
185+
self->peripheral->FIFO_b.DATA = self->last_write_data;
186+
} else {
187+
self->peripheral->S_b.DONE = true;
188+
}
189+
self->peripheral->DLEN_b.DLEN = len;
190+
self->peripheral->C = BSC0_C_READ_Msk | BSC0_C_ST_Msk | BSC0_C_I2CEN_Msk;
191+
// Wait for the transaction to start.
192+
while (self->peripheral->S_b.TA == 0) {
193+
RUN_BACKGROUND_TASKS;
194+
}
195+
for (size_t i = 0; i < len; i++) {
196+
if (self->peripheral->S_b.ERR) {
197+
break;
198+
}
199+
// Wait for the FIFO to have enough data that we can read it. RXR is low
200+
// once the transaction is done so we check the done bit too.
201+
while (!self->peripheral->S_b.RXR && !self->peripheral->S_b.DONE) {
202+
RUN_BACKGROUND_TASKS;
203+
}
204+
data[i] = self->peripheral->FIFO_b.DATA;
205+
}
206+
// Wait for the transaction to finish.
207+
while (!self->peripheral->S_b.DONE && !self->peripheral->S_b.ERR) {
208+
RUN_BACKGROUND_TASKS;
209+
}
210+
if (self->peripheral->S_b.ERR) {
211+
self->peripheral->S_b.ERR = true;
212+
while (self->peripheral->S_b.ERR == 1) {
213+
RUN_BACKGROUND_TASKS;
214+
}
215+
return MP_ENODEV;
216+
}
217+
218+
return 0;
101219
}
102220

103221
void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) {
104-
// never_reset_i2c[i2c_hw_index(self->peripheral)] = true;
222+
never_reset_i2c[self->index] = true;
105223

106-
never_reset_pin_number(self->scl_pin);
107-
never_reset_pin_number(self->sda_pin);
224+
common_hal_never_reset_pin(self->scl_pin);
225+
common_hal_never_reset_pin(self->sda_pin);
108226
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@
3131

3232
#include "py/obj.h"
3333

34+
#include "peripherals/broadcom/defines.h"
35+
#include "peripherals/broadcom/gpio.h"
36+
3437
typedef struct {
3538
mp_obj_base_t base;
39+
const mcu_pin_obj_t *scl_pin;
40+
const mcu_pin_obj_t *sda_pin;
41+
BSC0_Type *peripheral;
42+
uint8_t index;
3643
bool has_lock;
37-
uint baudrate;
38-
uint8_t scl_pin;
39-
uint8_t sda_pin;
44+
bool finish_write;
45+
uint8_t last_write_data;
4046
} busio_i2c_obj_t;
4147

4248
void reset_i2c(void);

0 commit comments

Comments
 (0)