I2C Module Problems with Grove Beginner Kit for Arduino

Hi Wayne_seltzer
I have tested other module without connecting 3-axis Acceleration, the problem occurs as you said, it may be that the module lacks a pull-up resistor, I need further confirmation, I will give you the answer tomorrow.

Best Regards
Fenyi

More test results:

Remove “3-axis Acceleration” and “Air Pressure” modules from the Grover Beginner Kit board.
Connect I2C cables for both modules.
No problems with test program, at the end of this note. (Combination of the OLED, motion, and pressure lessons.)

However, if you don’t connect the removed modules, the OLED will not work.
Why? On the OLED module, SDA and SCL have 10K pullup resistors to Vcc.
Need lower value pullups.
Solution: Add 4.7K resistors from SDA to Vcc and SCL to Vcc on an IIC connector.

Can someone at Seeed Studio verify my result?

What to do for people who have purchased these boards?

Those who have the old board: Provide a 3-axis acceleration module that fixes the 3.3v problem.
(Perhaps the Grove - 3-Axis Digital Accelerometer (LIS3DHTR) SKU 114020121) works with the beginner kit?)
(My students are not able to solder the rework wire. And, I can’t do it for them as our classes are remote.)

For all customers: Provide a Grove connector that includes 4.7K pullup resistors for SCL and SDA.
(Perhaps a modification to the Grove - I2C Hub (6 Port) SKU 103020272? Add pull-up resistors?)

I teach at two different schools. We would need to contact the people who purchased the beginner kits to determine what needs to be shipped where. (We can do this via email, not in the forum.)

Thanks,
Wayne

//Test I2C modules (OLED, pressure,accelerometer)
//OLED
#include <Arduino.h>
#include <U8x8lib.h>

U8X8_SSD1306_128X64_ALT0_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

//Accelerometer
#include "LIS3DHTR.h"
#include <Wire.h>
LIS3DHTR<TwoWire> LIS;           //Hardware I2C
#define WIRE Wire

//pressure
#include "Seeed_BMP280.h"
BMP280 bmp280;

void setup(void) {
  Serial.begin(9600);

  //OLED
  u8x8.begin();
  u8x8.setPowerSave(0);
  u8x8.setFlipMode(1);
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.clearDisplay();
  u8x8.setCursor(0, 0);
  u8x8.print("I2C module test");

  //Accelerometer
  Serial.println("LIS_accel init:");
  LIS.begin(WIRE, 0x19); //IIC init
  delay(50);
  LIS.setOutputDataRate(LIS3DHTR_DATARATE_50HZ);

  //pressure
  Serial.println("bmp280_pressure init:");
  if (!bmp280.init()) {
    Serial.println("Device not connected or broken!");
    u8x8.clearDisplay();
    u8x8.setCursor(0, 0);
    u8x8.print("bmp280 fail:  ");
  }
}

void loop(void) {
  u8x8.clearDisplay();
  u8x8.setCursor(0, 0);
  u8x8.print("Accl:  ");
  u8x8.print(abs(LIS.getAccelerationX()) + abs(LIS.getAccelerationY()) + abs(LIS.getAccelerationZ()));

  u8x8.setCursor(0, 1);
  u8x8.print("Press: ");
  u8x8.print(bmp280.getPressure());

  u8x8.setCursor(0, 2);
  u8x8.print("Temp:  ");
  u8x8.print(bmp280.getTemperature());

  delay(100);
}

Hi Wayne_seltzer
I figure out the problem.
Please review “https://wiki.seeedstudio.com/Grove-OLED-Display-0.96-SSD1315/”, there is a “FAQ” mention this problem.
if you just use OLED without other modules, you need to replace “U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8;” with “U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=/ SCL, / data=/ SDA, / reset=*/ U8X8_PIN_NONE);”.
if you use OLED connect with other modules, please put “U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8);”.

Best regards
Fenyi

1 Like

@fenyi: Can you please provide a sketch that works with the other modules removed?
Not working for me…

Hi Wayne_Seltzer

You can try to only connect OLED and remove other modules.
I attach the simple example below, it should be work.

#include <Arduino.h>
#include <U8x8lib.h>
 
// U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
 
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);   // OLEDs without Reset of the Display
 
void setup(void) {
  u8x8.begin();
  u8x8.setFlipMode(1);
}
 
void loop(void) {
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.setCursor(0, 0);
  u8x8.print("Hello World!");
}

Yes, software I2C works, even with the pullup resistor problem.
This is an OK workaround, but isn’t a fix for the hardware bug.
And, software I2C is slower, which could be a problem for some projects.

I’d rather use hardware I2C.
Will Seeed Studio be redesigning the Grove Beginner Kit to resolve this problem?
And, will existing customers get replacement boards?
Or, perhaps, some sort of Grove connector with pullup resistors?
(I’m using 3.9K pullups on the SDA and SCL lines when only the OLED is connected to the I2C bus.)
And will customers that have old boards get corrected 3-Axis Acceleration Modules?

Also, will Seeed Studio update the Lesson Guide to explain the issue, workarounds, and replacement process?

Without a complete resolution of the problem, I will not be able to continue to use the Grove Beginner Kit for my university and K-12 classes. I will mostly likely use the Sparkfun RedBoard with QWIIC modules instead.

Hi Wayne_Selzer

The Hardware I2C is work now.

You just need open “my pc” -> Documents -> Arduino -> libraries -> U8g2 -> src ->open U8x8lib.cpp -> Sliding to 1334 line -> delete or disable " Wire.setClock(u8x8->bus_clock); ".

Wire.setClock(u8x8->bus_clock);     // just delete or disable it

It should be work, and I will update the wiki ASAP.

Best regards
Fenyi

Hi @Fenyi,
Thank you for the suggestion to slow the I2C bus clock to address the OLED I2C pullup resistor problem. This is much better than using software I2C, which is very slow.

If one wants to use the fastest I2C speed with the OLED module and no other I2C modules, they will need to add pullup resistors to the the SDA and SCL lines. I found that 3.9K resistors allow the OLED
module to function at the default I2C bus speed.

Instead of editing the source of the u8g2 library, which will affect all uses of the library, it is preferable to set the I2C bus clock from the sketch.
We can use the .setBusClock() method, as described in the u8x8 reference.
Note that the clock rate cannot be an arbitrary value; an unsupported value will not cause an error but will use the default clock rate. (For details, refer to the ATMEGA328P documentation about the TWBR register.)

I wrote a small test program to determine the OLED update display rate for various I2C bus clock values as well as software I2C.
Results:

  • 400 KHz: 66 updates/sec. Fastest
    • does not work if there are no other I2C modules connected
    • works with 3.9K pullup resistors on SCL and SDA. (400KHz is the default clock rate)
  • 100 KHz: 33 updates/sec
  • 50 KHz: 22 updates/sec.
  • Software: 10 updates/sec. Slowest

My suggestions:

  • Document the OLED module problem on https://wiki.seeedstudio.com/Grove-Beginner-Kit-For-Arduino/#lesson-7-displaying-data-on-oled

  • Include instructions to add the pullup resistors if the fastest OLED display performance is desired when the other I2C modules connected.

  • Modify the OLED sketch to be sure that it works regardless of the connections of the other I2C modules. Change the setup() to include:

    void setup(void) {
    // slow down the I2C bus clock to enable the OLED to function
    // if the other I2C modules are removed from the board;
    // the default is 400000 (400 KHz)
    u8x8.setBusClock(100000);
    u8x8.begin();

Here’s a test program to compare display update speed with various clock rates:

#include <Arduino.h>
#include <U8x8lib.h>

//HW I2C:
U8X8_SSD1306_128X64_ALT0_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); //HW I2C

// SW I2C
//U8X8_SSD1306_128X64_ALT0_SW_I2C  u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);

unsigned long clockrates[] = { 50000L, 100000L, 400000L };
int iterations = 200;
int i;
unsigned long starttime;
int update_rate;
int prev_update_rate = 0;

void setup(void) {
  // slow down the I2C bus clock to enable the OLED to function
  // if the other I2C modules are removed from the board; 
  // the default is 400000 (400 KHz)
  u8x8.setBusClock(100000); 
  u8x8.begin();
  u8x8.setFlipMode(1);
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  Serial.begin(9600);
}

void loop(void) {
  Serial.println("OLED I2C bus clock test");
  Serial.println("");
  for (int c = 0; c < sizeof(clockrates) / sizeof(clockrates[0]); c++) {
    Serial.print("Clock rate: ");
    Serial.println(clockrates[c]);
    u8x8.setBusClock(clockrates[c]);
    u8x8.begin();
    u8x8.setFlipMode(1);
    u8x8.setFont(u8x8_font_chroma48medium8_r);
    starttime = millis();
    u8x8.clear();
    for (i = 1; i < iterations; i++) {
      update_rate = i / ((millis() - starttime) / 1000); //number of display updates per second
      u8x8.setCursor(0, 0);
      u8x8.print(clockrates[c]);
      u8x8.setCursor(0, 1);
      u8x8.print(i);
      if (update_rate != prev_update_rate) {
        u8x8.clearLine(2);
        u8x8.setCursor(0, 2);
        u8x8.print(update_rate);
        u8x8.setCursor(5, 2);
        u8x8.print("/sec");
        prev_update_rate = update_rate;
      }
      delay(1);
    }

    Serial.print(update_rate);
    Serial.println(" updates/second");
    Serial.println("");
  }
}

Thanks,
Wayne

1 Like

@Wayne_Seltzer Thank you for sharing. Have you tested the signal on the SDA data line when you were with 3.9K pull-up resistors on SCL and SDA? It doesn’t seem normal anymore.

hi Wayne_Seltzer

Thank you so much for your suggestion, I have tested your method, it works very well without the library code change, I will update it on the wiki.

Best regards
fenyi