Skip to content

Commit bb676f5

Browse files
committed
rp2/machine_i2c_target: Fix sequencing.
Signed-off-by: Damien George <[email protected]>
1 parent 2e68492 commit bb676f5

File tree

1 file changed

+45
-13
lines changed

1 file changed

+45
-13
lines changed

ports/rp2/machine_i2c_target.c

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ typedef struct _machine_i2c_target_obj_t {
7777
mp_hal_pin_obj_t sda;
7878
uint8_t state;
7979
bool stop_pending;
80+
bool irq_active;
8081
} machine_i2c_target_obj_t;
8182

8283
static machine_i2c_target_data_t i2c_target_data[4];
@@ -89,11 +90,26 @@ static machine_i2c_target_obj_t machine_i2c_target_obj[] = {
8990
/******************************************************************************/
9091
// RP2xxx hardware bindings
9192

93+
static void check_stop_pending(machine_i2c_target_obj_t *self) {
94+
if (self->irq_active) {
95+
return;
96+
}
97+
if (self->stop_pending && !(self->i2c_inst->hw->status & I2C_IC_STATUS_RFNE_BITS)) {
98+
unsigned int i2c_id = self - &machine_i2c_target_obj[0];
99+
machine_i2c_target_data_t *data = &i2c_target_data[i2c_id];
100+
self->stop_pending = false;
101+
self->state = STATE_IDLE;
102+
machine_i2c_target_data_restart_or_stop(data);
103+
}
104+
}
105+
92106
static void i2c_target_handler(i2c_inst_t *i2c) {
93107
unsigned int i2c_id = i2c == i2c0 ? 0 : 1;
94108
machine_i2c_target_obj_t *self = &machine_i2c_target_obj[i2c_id];
95109
machine_i2c_target_data_t *data = &i2c_target_data[i2c_id];
96110

111+
self->irq_active = true;
112+
97113
// Get the interrupt status.
98114
uint32_t intr_stat = i2c->hw->intr_stat;
99115

@@ -102,6 +118,16 @@ static void i2c_target_handler(i2c_inst_t *i2c) {
102118
(void)i2c->hw->clr_tx_abrt;
103119
}
104120

121+
if (intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) {
122+
// Controller sent a start condition.
123+
// Reset all state machines in case something went wrong.
124+
(void)i2c->hw->clr_start_det;
125+
if (self->state != STATE_IDLE) {
126+
machine_i2c_target_data_reset_helper(data);
127+
self->state = STATE_IDLE;
128+
}
129+
}
130+
105131
if (intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
106132
// Data from controller is available for reading.
107133
// Mask interrupt until I2C_DATA_CMD is read from.
@@ -138,6 +164,9 @@ static void i2c_target_handler(i2c_inst_t *i2c) {
138164
self->state = STATE_IDLE;
139165
}
140166
}
167+
168+
self->irq_active = false;
169+
check_stop_pending(self);
141170
}
142171

143172
static void i2c_slave_irq_handler(void) {
@@ -160,10 +189,12 @@ static void i2c_slave_init(i2c_inst_t *i2c, uint16_t addr, bool addr_10bit) {
160189
i2c->hw->sar = addr;
161190
i2c->hw->tx_tl = 1;
162191
i2c->hw->rx_tl = 0; // interrupt when at least 1 byte is available
192+
(void)i2c->hw->clr_intr;
163193

164194
// Enable interrupts.
165195
i2c->hw->intr_mask =
166-
I2C_IC_INTR_MASK_M_STOP_DET_BITS
196+
I2C_IC_INTR_MASK_M_START_DET_BITS
197+
| I2C_IC_INTR_MASK_M_STOP_DET_BITS
167198
| I2C_IC_INTR_MASK_M_RX_DONE_BITS
168199
| I2C_IC_INTR_MASK_M_TX_ABRT_BITS
169200
| I2C_IC_INTR_MASK_M_RD_REQ_BITS
@@ -187,6 +218,7 @@ static void i2c_slave_deinit(i2c_inst_t *i2c) {
187218

188219
i2c->hw->intr_mask = 0;
189220
i2c->hw->enable = 0;
221+
i2c->hw->con = I2C_IC_CON_IC_SLAVE_DISABLE_BITS;
190222
}
191223

192224
/******************************************************************************/
@@ -199,39 +231,36 @@ static void mp_machine_i2c_target_event_callback(machine_i2c_target_irq_obj_t *i
199231
mp_irq_handler(&irq->base);
200232
}
201233

202-
static mp_int_t mp_machine_i2c_target_read_bytes(machine_i2c_target_obj_t *self, size_t len, uint8_t *buf) {
234+
static size_t mp_machine_i2c_target_read_bytes(machine_i2c_target_obj_t *self, size_t len, uint8_t *buf) {
203235
i2c_hw_t *i2c_hw = self->i2c_inst->hw;
204236

205237
// Read from the RX FIFO.
206-
mp_int_t i = 0;
238+
size_t i = 0;
207239
while (i < len && (i2c_hw->status & I2C_IC_STATUS_RFNE_BITS)) {
208240
buf[i++] = i2c_hw->data_cmd;
209241
}
210242

211243
// Re-enable RX_FULL interrupt.
212244
i2c_hw->intr_mask |= I2C_IC_INTR_MASK_M_RX_FULL_BITS;
213245

214-
if (self->stop_pending && !(i2c_hw->status & I2C_IC_STATUS_RFNE_BITS)) {
215-
unsigned int i2c_id = self->i2c_inst == i2c0 ? 0 : 1;
216-
machine_i2c_target_data_t *data = &i2c_target_data[i2c_id];
217-
self->stop_pending = false;
218-
self->state = STATE_IDLE;
219-
machine_i2c_target_data_restart_or_stop(data);
220-
}
246+
check_stop_pending(self);
221247

222248
return i;
223249
}
224250

225-
static mp_int_t mp_machine_i2c_target_write_bytes(machine_i2c_target_obj_t *self, size_t len, const uint8_t *buf) {
251+
static size_t mp_machine_i2c_target_write_bytes(machine_i2c_target_obj_t *self, size_t len, const uint8_t *buf) {
226252
i2c_hw_t *i2c_hw = self->i2c_inst->hw;
227253

228254
// Write to the TX FIFO.
229-
i2c_hw->data_cmd = buf[0];
255+
size_t i = 0;
256+
while (i < len && (i2c_hw->status & I2C_IC_STATUS_TFNF_BITS)) {
257+
i2c_hw->data_cmd = buf[i++];
258+
}
230259

231260
// Re-enable RD_REQ interrupt.
232261
i2c_hw->intr_mask |= I2C_IC_INTR_MASK_M_RD_REQ_BITS;
233262

234-
return 1;
263+
return i;
235264
}
236265

237266
static void mp_machine_i2c_target_irq_config(machine_i2c_target_obj_t *self, unsigned int trigger) {
@@ -271,6 +300,7 @@ static mp_obj_t mp_machine_i2c_target_make_new(const mp_obj_type_t *type, size_t
271300
// Initialise data.
272301
self->state = STATE_IDLE;
273302
self->stop_pending = false;
303+
self->irq_active = false;
274304
MP_STATE_PORT(i2c_target_mem_obj)[i2c_id] = args[ARG_mem].u_obj;
275305
machine_i2c_target_data_t *data = &i2c_target_data[i2c_id];
276306
machine_i2c_target_data_init(data, args[ARG_mem].u_obj, args[ARG_mem_addrsize].u_int);
@@ -310,5 +340,7 @@ static void mp_machine_i2c_target_print(const mp_print_t *print, mp_obj_t self_i
310340
}
311341

312342
static void mp_machine_i2c_target_deinit(machine_i2c_target_obj_t *self) {
343+
gpio_set_function(self->scl, GPIO_FUNC_SIO);
344+
gpio_set_function(self->sda, GPIO_FUNC_SIO);
313345
i2c_slave_deinit(self->i2c_inst);
314346
}

0 commit comments

Comments
 (0)