I’m trying to talk to an board via I2C. The board is called Dr. Wattson and is based on Microchip’s MCP39F521. I have an Arduino library called UpbeatLabs_MCP39F521 that I ported to Particle.
The board has bidirectional level shifters for the SDA/SCL lines using BSS138 . The device works fine with Arduino Uno (5v), Arduino Pro Mini 3.3v, Raspberry Pi (3.3v with an equivalent Python library), Arduino Nano 33 BLE Sense, Raspberry Pi Pico (3.3v) with CircuitPython. The board is powered by 3.3v and the MCU side has a VIN for logic level voltage to pull up to - 3.3v or 5v.
However, with the Particle Photon (running DeviceOS 3.3.0), I’m not getting any data response from the device. After writing to some registers to request data, I call Wire.requestFrom to read the data, followed by Wire.available(), which returns 0.
I’ve attached the high-level schematic. Logic analyzer shows proper message being sent by Particle, but then there’s no response.
If I pull the SCL wire and reconnect it, I can get a response (whose data also looks ok), but subsequent calls fail in the same way as described above (Wire.available gives 0), which seems to suggest issues with pulling down the signal to low?
I’ve tried with external pullups (above the 10k of the bidirectional level shifters) - 2k, 10k, no pullups. setting the pinMode on the I2C pins (to disable any pullups) seems to have no effect - getPinMode always returns 5 (AF_OUTPUT_DRAIN) The comments say
// Used internally for Alternate Function Output Drain(I2C etc). External pullup resistors required.
I thought I2C has internal pullups enabled by default, and I also tried to set pinMode differently to disable any internal pullups, but getPinMode always returns 5.
I’m not sure definitively if there is any internal pullup enabled on the I2C pins of the Particle Photon (the older version), and if so, how I may be able to disable the pullup (seeing as pinMode above has no effect when using Wire library).
The code is fairly straightforward:
int UpbeatLabs_MCP39F521::registerReadNBytes(int addressHigh, int addressLow,
int numBytesToRead, uint8_t *byteArray,
int byteArraySize)
{
uint8_t i2c_bus_Status = 0;
uint8_t aucWriteDataBuf[8];
int i;
uint32_t checksumTotal = 0;
if (byteArraySize < numBytesToRead + 3) {
return ERROR_INSUFFICIENT_ARRAY_SIZE;
}
aucWriteDataBuf[0] = 0xa5; // Header
aucWriteDataBuf[1] = 0x08; // Num bytes
aucWriteDataBuf[2] = COMMAND_SET_ADDRESS_POINTER; // Command - set address pointer
aucWriteDataBuf[3] = addressHigh;
aucWriteDataBuf[4] = addressLow;
aucWriteDataBuf[5] = COMMAND_REGISTER_READ_N_BYTES; // Command - read register, N bytes
aucWriteDataBuf[6] = numBytesToRead;
aucWriteDataBuf[7] = 0; // Checksum - computed below
for(i=0; i<7;i++) {
checksumTotal += aucWriteDataBuf[i];
}
aucWriteDataBuf[7] = checksumTotal % 256;
Wire.beginTransmission(i2c_addr);
for(i=0; i< 8; i++) {
Wire.write(aucWriteDataBuf[i]);
}
i2c_bus_Status = Wire.endTransmission();
wireErrors(i2c_bus_Status);
delay(1);
//
// Read the specified length of data - numBytesToRead + 3 bytes
//
Wire.requestFrom(i2c_addr, numBytesToRead + 3); <<<-----------------
int requestDataLength = Wire.available(); <<<<<<----------------------- this is always 0
Serial.print("Num bytes to read2 + 3 = ");Serial.print(numBytesToRead + 3); Serial.println();
Serial.print("Requested data length = ");Serial.print(requestDataLength); Serial.println();
if (requestDataLength==(numBytesToRead + 3)) {
for (i = 0; i < numBytesToRead + 3 ; i++) {
byteArray[i] = Wire.read();
Serial.print(byteArray[i], HEX); Serial.print(" ");
}
Serial.print("\n");
// Check header and checksum
return checkHeaderAndChecksum(numBytesToRead, byteArray, byteArraySize);
} else {
// Unexpected. Handle error
return ERROR_UNEXPECTED_RESPONSE;
}
return SUCCESS;
}
Any help will be appreciated!
Thanks,
Sridhar