Skip to content

Commit 7cd3f2f

Browse files
committed
pbio/drv/i2c_ev3: Retry once on NAK.
A single retry appears sufficient so far. Fixes pybricks/support#2314
1 parent 8346ad3 commit 7cd3f2f

File tree

1 file changed

+52
-43
lines changed

1 file changed

+52
-43
lines changed

lib/pbio/drv/i2c/i2c_ev3.c

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
// Rounded up to a nice power of 2 and multiple of cache lines
4444
#define PRU_I2C_MAX_BYTES_PER_TXN 512
4545

46+
// Number of times we try the operation before NAK is raised as an IO error.
47+
#define PRU_I2C_MAX_NUM_TRIES_ON_NAK (2)
48+
4649
static uint8_t pbdrv_i2c_buffers[PBDRV_RPROC_EV3_PRU1_NUM_I2C_BUSES][PRU_I2C_MAX_BYTES_PER_TXN] PBDRV_DMA_BUF;
4750

4851
struct _pbdrv_i2c_dev_t {
@@ -51,6 +54,7 @@ struct _pbdrv_i2c_dev_t {
5154
bool is_initialized;
5255
uint8_t pru_i2c_idx;
5356
pbio_os_timer_t timer;
57+
size_t try_count;
5458
};
5559

5660
static pbdrv_i2c_dev_t i2c_devs[PBDRV_RPROC_EV3_PRU1_NUM_I2C_BUSES];
@@ -131,53 +135,58 @@ pbio_error_t pbdrv_i2c_write_then_read(
131135
memcpy(i2c_dev->buffer, wdata, wlen);
132136
}
133137

134-
if (nxt_quirk) {
135-
// NXT sensors affected by the quirk can't be accessed too quickly.
136-
// This ensures a minimum delay without slowing down code that polls
137-
// less frequently.
138-
PBIO_OS_AWAIT_UNTIL(state, pbio_os_timer_is_expired(&i2c_dev->timer));
139-
pbio_os_timer_set(&i2c_dev->timer, 100);
140-
}
141-
142-
i2c_dev->is_busy = true;
143-
pbdrv_cache_prepare_before_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
144-
145-
// Kick off transfer
146-
pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags = PBDRV_RPROC_EV3_PRU1_I2C_PACK_FLAGS(
147-
dev_addr,
148-
rlen,
149-
wlen,
150-
PBDRV_RPROC_EV3_PRU1_I2C_CMD_START | (nxt_quirk ? PBDRV_RPROC_EV3_PRU1_I2C_CMD_NXT_QUIRK : 0)
151-
);
152-
153-
// Wait for transfer to finish
154-
PBIO_OS_AWAIT_WHILE(state, i2c_dev->is_busy);
155-
156-
uint32_t flags = pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags;
157-
debug_pr("i2c %d done flags %08x\r\n", i2c_dev->pru_i2c_idx, flags);
158-
if (!(flags & PBDRV_RPROC_EV3_PRU1_I2C_STAT_DONE)) {
159-
debug_pr("i2c %d not actually done???\r\n", i2c_dev->pru_i2c_idx);
160-
return PBIO_ERROR_FAILED;
161-
}
162-
switch (flags & PBDRV_RPROC_EV3_PRU1_I2C_STAT_MASK) {
163-
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_OK:
164-
break;
165-
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_TIMEOUT:
138+
for (i2c_dev->try_count = 0; i2c_dev->try_count < PRU_I2C_MAX_NUM_TRIES_ON_NAK; i2c_dev->try_count++) {
139+
140+
if (nxt_quirk) {
141+
// NXT sensors affected by the quirk can't be accessed too quickly.
142+
// The timer is set after awaiting so we don't unnecessarily slow
143+
// down code that polls less frequently.
144+
PBIO_OS_AWAIT_UNTIL(state, pbio_os_timer_is_expired(&i2c_dev->timer));
145+
pbio_os_timer_set(&i2c_dev->timer, 100);
146+
}
147+
148+
i2c_dev->is_busy = true;
149+
pbdrv_cache_prepare_before_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
150+
151+
// Kick off transfer
152+
pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags = PBDRV_RPROC_EV3_PRU1_I2C_PACK_FLAGS(
153+
dev_addr,
154+
rlen,
155+
wlen,
156+
PBDRV_RPROC_EV3_PRU1_I2C_CMD_START | (nxt_quirk ? PBDRV_RPROC_EV3_PRU1_I2C_CMD_NXT_QUIRK : 0)
157+
);
158+
159+
// Wait for transfer to finish
160+
PBIO_OS_AWAIT_WHILE(state, i2c_dev->is_busy);
161+
162+
uint32_t flags = pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags;
163+
debug_pr("i2c %d done flags %08x\r\n", i2c_dev->pru_i2c_idx, flags);
164+
if (!(flags & PBDRV_RPROC_EV3_PRU1_I2C_STAT_DONE)) {
165+
debug_pr("i2c %d not actually done\r\n", i2c_dev->pru_i2c_idx);
166+
return PBIO_ERROR_FAILED;
167+
}
168+
169+
flags &= PBDRV_RPROC_EV3_PRU1_I2C_STAT_MASK;
170+
171+
if (flags == PBDRV_RPROC_EV3_PRU1_I2C_STAT_OK) {
172+
// Success, exit loop.
173+
pbdrv_cache_prepare_after_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
174+
if (rlen) {
175+
*rdata = &i2c_dev->buffer[wlen];
176+
}
177+
return PBIO_SUCCESS;
178+
} else if (flags == PBDRV_RPROC_EV3_PRU1_I2C_STAT_TIMEOUT) {
166179
return PBIO_ERROR_TIMEDOUT;
167-
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_NAK:
168-
return PBIO_ERROR_IO;
169-
default:
170-
debug_pr("i2c %d unknown error occurred???\r\n", i2c_dev->pru_i2c_idx);
180+
} else if (flags != PBDRV_RPROC_EV3_PRU1_I2C_STAT_NAK) {
181+
// Many known NXT devices occasionally get NAK. Retrying usually
182+
// helps. Everything else is unexpected and raised immediately.
183+
debug_pr("i2c %d unknown error occurred\r\n", i2c_dev->pru_i2c_idx);
171184
return PBIO_ERROR_FAILED;
185+
}
172186
}
173187

174-
// If we got here, there's no error. Tell caller where to read RX data.
175-
pbdrv_cache_prepare_after_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
176-
if (rlen) {
177-
*rdata = &i2c_dev->buffer[wlen];
178-
}
179-
180-
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
188+
// Didn't succeed even after trying allowed number of times.
189+
PBIO_OS_ASYNC_END(PBIO_ERROR_IO);
181190
}
182191

183192
static pbio_os_process_t ev3_i2c_init_process;

0 commit comments

Comments
 (0)