adafruit / adafruit/Adafruit_nRF52_Arduino

TwoWire library crashes, when quantity parameter in request_from() function is greater than SERIAL_BUFFER_SIZE.

Open
#858 0 comments 0 reactions 0 assignees View on GitHub
Bug
Dominant language
C
Stars
699
Forks
570
PR merge metrics
No merged PRs in 30d

Description

### Operating System

Windows 11

### IDE version

Arduino 2.3.5

### Board

XIAO nRF52840

### BSP version

Seed nRF52 Boards 1.1.12

### Sketch

/*
AT24eeprom - Arduino libary for driving the AT24 I2 based eeproms Copyright (c)
2025 Wolfgang Schmieder. All right reserved.

Contributors:
- Wolfgang Schmieder

Project home: https://github.com/dac1e/AT24eeprom/

This library is free software; you can redistribute it and/or modify it
the terms of the GNU Lesser General Public License as under published
by the Free Software Foundation; either version 3.0 of the License,
or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**
* Note: The main purpose of this sketch is to reproduce a bug in the nRF52840 TwoWire driver.
*/

#include "Arduino.h"

#include
#include "AT24CxEeprom.h"

#if defined SIZE_MAX
static size_t sizeMax() {return SIZE_MAX;}
#else
#include
static size_t sizeMax() {return std::numeric_limits::max();}
#endif

class MYAT24C512 : public AT24C512 {
public:
MYAT24C512(TwoWire &wire, uint8_t deviceAddress) : AT24C512(wire, deviceAddress) {
}
private:
// We override this function so that read quantity is not artificially limited.
// Hence the TwoWire driver has to take care, that there is no read buffer
// overrun.
virtual size_t maxBulkReadQuantity() const override {
return sizeMax();
}
};

static MYAT24C512 eeprom(Wire, 0);

static typeof(Serial)& output = Serial;
//static typeof(Serial1)& output = Serial1;

static void fillBuffer(uint8_t* buffer, size_t bytesCount, uint8_t pattern) {
for(size_t i=0; i< bytesCount; i++) {
buffer[i] = pattern;
}
}

static bool writeReadAndCompare(size_t bytesCount, uint8_t pattern, uint16_t eepromAddress) {
uint8_t* writeBuffer = new uint8_t [bytesCount];

fillBuffer(writeBuffer, bytesCount, pattern);
eeprom.write(eepromAddress, writeBuffer , bytesCount);

delay(1);

uint8_t* readBuffer = new uint8_t [bytesCount];
eeprom.read(eepromAddress,readBuffer, bytesCount);

const bool result = (memcmp(readBuffer, writeBuffer, bytesCount) == 0);

delete[] readBuffer;
delete[] writeBuffer;

return result;
}

static void testWriteRead(uint8_t pattern) {
const size_t count = eeprom.pageSize();
const uint16_t eepromAddress = 0x08;

output.print("Write and read ");
output.print(count);
output.print(" times pattern ");
output.print(pattern, HEX);
output.print(" at address ");
output.print(eepromAddress, HEX);
output.print(" ... ");

// Write to and read back from eeprom adress
const bool bOk = writeReadAndCompare(eeprom.pageSize(), pattern, eepromAddress);

if(bOk) {
output.println(" Pass!");
} else {
output.println(" Fail!");
}
}

static size_t constexpr LOOPS = 3;
static size_t nRemainingLoops = LOOPS;

//The setup function is called once at startup of the sketch
void setup()
{
output.begin(115200);
output.println();
output.println("Starting write/read test.");
eeprom.begin();
}

// The loop function is called in an endless loop
void loop()
{
delay(3000);
if(nRemainingLoops) {
--nRemainingLoops;
output.println();
output.print("Executing test loop #");
output.println(LOOPS - nRemainingLoops);
testWriteRead(0x55);
testWriteRead(0xAA);
if(not nRemainingLoops) {
output.println();
output.println("Test finished.");
}
}
}

### What happened ?

The library AT24CxEeprom is required to run the sketch. When connecting an AT24C512 and trying to read a complete eeprom page with a size of 128 Bytes, the processor reboots. It seems that the RingBuffer is corrupted. When only half of a page (64 bytes) are requested, everything works properly. Ist seems that the crash happens, when the requested quantity of bytes is greater than SERIAL_BUFFER

### How to reproduce ?

Just take the provided sketch and add the recent version of library AT24CxEeprom.

### Debug Log

_No response_

### Screenshots

_No response_

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with Wire.h and the nRF52840 TwoWire driver, focusing on request_from(), SERIAL_BUFFER_SIZE, and the RingBuffer behavior described in the reproduction sketch. Re-run the supplied AT24CxEeprom sketch with 128-byte and 64-byte reads; done means the larger request no longer reboots the processor or corrupts the ring buffer.

Written by the indexing model from the issue text.

Assessment

Tech stack
arduino, c
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.