Skip to content

Commit df65c45

Browse files
committed
All Arduino and AdaFruit SAMD boards with a flash-based bootloader have
a bug where reading 64 bytes or more over USB returns corrupted data. This is because the bootloaders try to send 64+ byte USB packets with a pointer into flash instead of SRAM which is not allowed on the SAMD. Instead we detect the Arduino bootloader and break read transactions into multiple requests no larger than 63 bytes.
1 parent 66dd8cf commit df65c45

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

src/Samba.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Samba::Samba() :
5656
_canChipErase(false),
5757
_canWriteBuffer(false),
5858
_canChecksumBuffer(false),
59+
_readBufferSize(0),
5960
_debug(false),
6061
_isUsb(false)
6162
{
@@ -122,6 +123,12 @@ Samba::init()
122123
}
123124
extIndex++;
124125
}
126+
127+
// All SAMD-based Arduino/AdaFruit boards have a bug in their bootloader
128+
// that trying to read 64 bytes or more over USB corrupts the data.
129+
// We must limit these boards to read chunks of 63 bytes.
130+
if (_isUsb)
131+
_readBufferSize = 63;
125132
}
126133

127134
_port->timeout(TIMEOUT_NORMAL);
@@ -452,29 +459,43 @@ void
452459
Samba::read(uint32_t addr, uint8_t* buffer, int size)
453460
{
454461
uint8_t cmd[20];
462+
int chunk;
455463

456464
if (_debug)
457465
printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size);
458466

459467
// The SAM firmware has a bug reading powers of 2 over 32 bytes
460468
// via USB. If that is the case here, then read the first byte
461469
// with a readByte and then read one less than the requested size.
462-
if (_isUsb && size > 32 && !(size & (size - 1)))
470+
if (_isUsb && _readBufferSize == 0 && size > 32 && !(size & (size - 1)))
463471
{
464472
*buffer = readByte(addr);
465473
addr++;
466474
buffer++;
467475
size--;
468476
}
469477

470-
snprintf((char*) cmd, sizeof(cmd), "R%08X,%08X#", addr, size);
471-
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
472-
throw SambaError();
478+
while (size > 0)
479+
{
480+
// Handle any limitations on the size of the read
481+
if (_readBufferSize > 0 && size > _readBufferSize)
482+
chunk = _readBufferSize;
483+
else
484+
chunk = size;
473485

474-
if (_isUsb)
475-
readBinary(buffer, size);
476-
else
477-
readXmodem(buffer, size);
486+
snprintf((char*) cmd, sizeof(cmd), "R%08X,%08X#", addr, chunk);
487+
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
488+
throw SambaError();
489+
490+
if (_isUsb)
491+
readBinary(buffer, chunk);
492+
else
493+
readXmodem(buffer, chunk);
494+
495+
size -= chunk;
496+
addr += chunk;
497+
buffer += chunk;
498+
}
478499
}
479500

480501
void

src/Samba.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Samba
9393
bool _canChipErase;
9494
bool _canWriteBuffer;
9595
bool _canChecksumBuffer;
96+
int _readBufferSize;
9697
bool _debug;
9798
bool _isUsb;
9899
SerialPort::Ptr _port;

0 commit comments

Comments
 (0)