Read immediately after I2C write

I am using the jdy-16 bluetooth module and I am having a hard time interacting with it over I2C. According to the datasheet (see below), the procedure for reading from the device is to :

  1. write the device address
  2. write the desired register address (“internal function address” in the datasheet)
  3. read the desire register value
  4. (data follows from device to microcontroller - “Data N” in the datasheet)

The problem is between steps 2 and 3. The actual reading is implemented as Wire.requestFrom(deviceAddress, numberOfBytes). Which puts the device address again on the bus, contradicting the datasheet.

Any thoughts how to circumvent this?

Many thanks in advance!

… or perhaps there is a way to publicly inherit from Wire and override the requestFrom() method? - I have tried but am getting compile errors within the Wire header.

That looks like a pretty standard I2C protocol transaction.

  1. Do a Wire.beginTransmission(deviceAddr)
  2. Do a Wire.write(internalFunctionAddr) then Wire.endTransmission(false). The false is necessary so the stop is not sent so you can do the read next.
    3/4: Do a Wire.requestFrom(deviceAddr, quantity)

There is a second address sent after Internal Function Address, as is typical for I2C. Just make sure you endTransmission(false) otherwise there will be a stop and the transaction will be wrong.

That’s what I thought. Yet the module isn’t sending anything back. After debugging the for a couple of hours, I came up with the code below. The problem I suspect, is that the module expects an I2C read immediately after the master wrote the register address. At least it’s the way I interpret the snippet in the datasheet. A DSO probing session reveals that requestFrom puts the module’s address again on the bus (screenshot below).

It may be the I2C communication is non-standard.

static inline void readI2CBytes(const uint8_t destination_address,
                               const uint16_t register_address) {
  uint8_t transmission_status = 255;
    

    Wire.beginTransmission(destination_address);
    Wire.write(static_cast<uint8_t>(register_address));
    
    transmission_status = Wire.endTransmission();
    
  uint8_t count = Wire.requestFrom(destination_address, 1);
  while (!Wire.available())    {Particle.process();};
  for(uint8_t i = 0 ; i < count; ++i){
    if (Wire.available()) {
       Serial.write("Got2 :"+ Wire.read());
    }
  }
}

void setup() {
    Wire.setSpeed(50000);
    Wire.begin();
    delay(1000);
    
Serial.begin(9600);

}

void loop() {
    readI2CBytes(0x50, 0x31);
    delay(500);
}

Wire.endTransmission();

You’re missing the false parameter. Without the false the device doesn’t know you’re going to read next.

1 Like

oh, man. This was a loong day.
Thank you, it works now!

1 Like