Skip to content

Commit 50dd024

Browse files
adeebshihadehComma Device
and
Comma Device
authored
pandad/SPI: ensure slave is in a consistent state (#32645)
* maxout * get ready for the next one * really get ready * much better --------- Co-authored-by: Comma Device <[email protected]> old-commit-hash: f8cb04e
1 parent 0ee93c6 commit 50dd024

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

selfdrive/pandad/panda.cc

+5
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ bool Panda::can_receive(std::vector<can_frame>& out_vec) {
221221
return false;
222222
}
223223

224+
if (getenv("PANDAD_MAXOUT") != NULL) {
225+
static uint8_t junk[RECV_SIZE];
226+
handle->bulk_read(0xab, junk, RECV_SIZE - recv);
227+
}
228+
224229
bool ret = true;
225230
if (recv > 0) {
226231
receive_buffer_size += recv;

selfdrive/pandad/spi.cc

+31-14
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ class LockEx {
5050

5151
#define SPILOG(fn, fmt, ...) do { \
5252
fn(fmt, ## __VA_ARGS__); \
53-
fn(" %d / 0x%x / %d / %d", \
54-
xfer_count, header.endpoint, header.tx_len, header.max_rx_len); \
53+
fn(" %d / 0x%x / %d / %d / tx: %s", \
54+
xfer_count, header.endpoint, header.tx_len, header.max_rx_len, \
55+
util::hexdump(tx_buf, std::min((int)header.tx_len, 8)).c_str()); \
5556
} while (0)
5657

5758
PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) {
@@ -238,6 +239,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1
238239
// due to full TX buffers
239240
nack_count += 1;
240241
if (nack_count > 3) {
242+
SPILOG(LOGE, "NACK sleep %d", nack_count);
241243
usleep(std::clamp(nack_count*10, 200, 2000));
242244
}
243245
}
@@ -256,14 +258,14 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
256258
if (timeout == 0) {
257259
timeout = SPI_ACK_TIMEOUT;
258260
}
259-
timeout = std::clamp(timeout, 100U, SPI_ACK_TIMEOUT);
261+
timeout = std::clamp(timeout, 20U, SPI_ACK_TIMEOUT);
260262

261263
spi_ioc_transfer transfer = {
262264
.tx_buf = (uint64_t)tx_buf,
263265
.rx_buf = (uint64_t)rx_buf,
264-
.len = length
266+
.len = length,
265267
};
266-
tx_buf[0] = tx;
268+
memset(tx_buf, tx, length);
267269

268270
while (true) {
269271
int ret = lltransfer(transfer);
@@ -275,13 +277,13 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
275277
if (rx_buf[0] == ack) {
276278
break;
277279
} else if (rx_buf[0] == SPI_NACK) {
278-
SPILOG(LOGD, "SPI: got NACK");
280+
SPILOG(LOGD, "SPI: got NACK, waiting for 0x%x", ack);
279281
return SpiError::NACK;
280282
}
281283

282284
// handle timeout
283285
if (millis_since_boot() - start_millis > timeout) {
284-
SPILOG(LOGW, "SPI: timed out waiting for ACK");
286+
SPILOG(LOGW, "SPI: timed out waiting for ACK, waiting for 0x%x", ack);
285287
return SpiError::ACK_TIMEOUT;
286288
}
287289
}
@@ -352,13 +354,13 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
352354
ret = lltransfer(transfer);
353355
if (ret < 0) {
354356
SPILOG(LOGE, "SPI: failed to send header");
355-
return ret;
357+
goto fail;
356358
}
357359

358360
// Wait for (N)ACK
359361
ret = wait_for_ack(SPI_HACK, 0x11, timeout, 1);
360362
if (ret < 0) {
361-
return ret;
363+
goto fail;
362364
}
363365

364366
// Send data
@@ -370,38 +372,53 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
370372
ret = lltransfer(transfer);
371373
if (ret < 0) {
372374
SPILOG(LOGE, "SPI: failed to send data");
373-
return ret;
375+
goto fail;
374376
}
375377

376378
// Wait for (N)ACK
377379
ret = wait_for_ack(SPI_DACK, 0x13, timeout, 3);
378380
if (ret < 0) {
379-
return ret;
381+
goto fail;
380382
}
381383

382384
// Read data
383385
rx_data_len = *(uint16_t *)(rx_buf+1);
384386
if (rx_data_len >= SPI_BUF_SIZE) {
385387
SPILOG(LOGE, "SPI: RX data len larger than buf size %d", rx_data_len);
386-
return -1;
388+
goto fail;
387389
}
388390

389391
transfer.len = rx_data_len + 1;
390392
transfer.rx_buf = (uint64_t)(rx_buf + 2 + 1);
391393
ret = lltransfer(transfer);
392394
if (ret < 0) {
393395
SPILOG(LOGE, "SPI: failed to read rx data");
394-
return ret;
396+
goto fail;
395397
}
396398
if (!check_checksum(rx_buf, rx_data_len + 4)) {
397399
SPILOG(LOGE, "SPI: bad checksum");
398-
return -1;
400+
goto fail;
399401
}
400402

401403
if (rx_data != NULL) {
402404
memcpy(rx_data, rx_buf + 3, rx_data_len);
403405
}
404406

405407
return rx_data_len;
408+
409+
fail:
410+
// ensure slave is in a consistent state
411+
// and ready for the next transfer
412+
int nack_cnt = 0;
413+
while (nack_cnt < 3) {
414+
if (wait_for_ack(SPI_NACK, 0x14, 1, SPI_BUF_SIZE/2) == 0) {
415+
nack_cnt += 1;
416+
} else {
417+
nack_cnt = 0;
418+
}
419+
}
420+
421+
if (ret > 0) ret = -1;
422+
return ret;
406423
}
407424
#endif

selfdrive/pandad/tests/test_pandad_spi.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def test_spi_corruption(self, subtests):
9797
with subtests.test(msg="timing check", service=service):
9898
edt = 1e3 / SERVICE_LIST[service].frequency
9999
assert edt*0.9 < np.mean(dts) < edt*1.1
100-
assert np.max(dts) < edt*20
100+
assert np.max(dts) < edt*8
101101
assert np.min(dts) < edt
102102
assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8)
103103

0 commit comments

Comments
 (0)