How to use this OLED library with a second i2c port?

I'm attempting to use the Adafruit SH1106 library, which is an adaptation of the Adafruit SSD1306 library, but for the 1.3" SH1106 display instead of the .96" SSD1306.

I've used the SSD1306 library, which worked fine, because defining the class involves saying which i2c port you're using, so I put "&Wire1". Very simple.

However this kind user changed the function so that only the 'reset' pin needs to be defined, which makes it easier for people using the default i2c port, but now I do not know how to tell it that I'm using the second i2c port.

In the header file, the only similar thing that I can find are these lines at the very top.

#if ARDUINO >= 100
 #include "Arduino.h"
 #define WIRE_WRITE Wire.write
#else
 #include "WProgram.h"
  #define WIRE_WRITE Wire.send
#endif

My attempts to change Wire.write and Wire.send to "Wire1.write" and "Wire1.send" did not succeed. Looking through the .h and .cpp files, all references to the wire library stem from these definitions.
How do I adapt this library to use my second i2c port? Thanks.

Why do you think you need a second I2C port? I2C is a bus, and supports multiple devices in parallel.

Currently that port is being used by an i2c device that has resistors soldered to it (an Adafruit Trellis which is 5v, into a level shifter). The Trellis works fine but I'm not sure if the OLED will work with the resistors in the way.

Eventually, those will also move to another i2c port and be replaced by the Teensy Audio board, which physically sits on top of the Teensy, and occupies the first i2c port for Audio. I suppose I could then use the audio board and the OLED from the same port, but I figured that asking here would be a learning experience regardless.

How do I adapt this library to use my second i2c port?

Edit the library to use a reference to the Wire device in question?

The I2C bus requires pullup resistors on SDA and SCL, and won't work without them.

The total parallel value of all the pullup resistors on the bus should be somewhere in the range 2.2K to 4.7K, so you have to check all the devices that are attached, and whether or not they have pullup resistors.

You may have to add or remove resistors, and you will also need level shifters to connect 3.3V and 5V devices.

Edit the library to use a reference to the Wire device in question?

I have made this post because I do not know how to do this.

Please refer to the part of my post with the code. As I said, replacing Wire with Wire1 had no effect. Clearly this is not correct, so I am here to ask what I should be doing.

coryoryoh:
Please refer to the part of my post with the code.

I can’t see your code.

The header file is where Wire.write and Wire.send are used.

Adafruit_SH1106.h:

#if ARDUINO >= 100
 #include "Arduino.h"
 #define WIRE_WRITE Wire.write
#else
 #include "WProgram.h"
  #define WIRE_WRITE Wire.send
#endif

#ifdef __SAM3X8E__
 typedef volatile RwReg PortReg;
 typedef uint32_t PortMask;
#else
  typedef volatile uint8_t PortReg;
  typedef uint8_t PortMask;
#endif

#include <SPI.h>
#include <Adafruit_GFX.h>

#define BLACK 0
#define WHITE 1
#define INVERSE 2

#define SH1106_I2C_ADDRESS   0x3C // 011110+SA0+RW - 0x3C or 0x3D
// Address for 128x32 is 0x3C
// Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded)

/*=========================================================================
    SH1106 Displays
    -----------------------------------------------------------------------
    The driver is used in multiple displays (128x64, 128x32, etc.).
    Select the appropriate display below to create an appropriately
    sized framebuffer, etc.

    SH1106_128_64  128x64 pixel display

    SH1106_128_32  128x32 pixel display

    SH1106_96_16

    -----------------------------------------------------------------------*/
   #define SH1106_128_64
//   #define SH1106_128_32
//   #define SH1106_96_16
/*=========================================================================*/

#if defined SH1106_128_64 && defined SH1106_128_32
  #error "Only one SH1106 display can be specified at once in SH1106.h"
#endif
#if !defined SH1106_128_64 && !defined SH1106_128_32 && !defined SH1106_96_16
  #error "At least one SH1106 display must be specified in SH1106.h"
#endif

#if defined SH1106_128_64
  #define SH1106_LCDWIDTH                  128
  #define SH1106_LCDHEIGHT                 64
#endif
#if defined SH1106_128_32
  #define SH1106_LCDWIDTH                  128
  #define SH1106_LCDHEIGHT                 32
#endif
#if defined SH1106_96_16
  #define SH1106_LCDWIDTH                  96
  #define SH1106_LCDHEIGHT                 16
#endif

#define SH1106_SETCONTRAST 0x81
#define SH1106_DISPLAYALLON_RESUME 0xA4
#define SH1106_DISPLAYALLON 0xA5
#define SH1106_NORMALDISPLAY 0xA6
#define SH1106_INVERTDISPLAY 0xA7
#define SH1106_DISPLAYOFF 0xAE
#define SH1106_DISPLAYON 0xAF

#define SH1106_SETDISPLAYOFFSET 0xD3
#define SH1106_SETCOMPINS 0xDA

#define SH1106_SETVCOMDETECT 0xDB

#define SH1106_SETDISPLAYCLOCKDIV 0xD5
#define SH1106_SETPRECHARGE 0xD9

#define SH1106_SETMULTIPLEX 0xA8

#define SH1106_SETLOWCOLUMN 0x00
#define SH1106_SETHIGHCOLUMN 0x10

#define SH1106_SETSTARTLINE 0x40

#define SH1106_MEMORYMODE 0x20
#define SH1106_COLUMNADDR 0x21
#define SH1106_PAGEADDR   0x22

#define SH1106_COMSCANINC 0xC0
#define SH1106_COMSCANDEC 0xC8

#define SH1106_SEGREMAP 0xA0

#define SH1106_CHARGEPUMP 0x8D

#define SH1106_EXTERNALVCC 0x1
#define SH1106_SWITCHCAPVCC 0x2

// Scrolling #defines
#define SH1106_ACTIVATE_SCROLL 0x2F
#define SH1106_DEACTIVATE_SCROLL 0x2E
#define SH1106_SET_VERTICAL_SCROLL_AREA 0xA3
#define SH1106_RIGHT_HORIZONTAL_SCROLL 0x26
#define SH1106_LEFT_HORIZONTAL_SCROLL 0x27
#define SH1106_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
#define SH1106_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A

class Adafruit_SH1106 : public Adafruit_GFX {
 public:
  Adafruit_SH1106(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS);
  Adafruit_SH1106(int8_t DC, int8_t RST, int8_t CS);
  Adafruit_SH1106(int8_t RST);

  void begin(uint8_t switchvcc = SH1106_SWITCHCAPVCC, uint8_t i2caddr = SH1106_I2C_ADDRESS, bool reset=true);
  void SH1106_command(uint8_t c);
  void SH1106_data(uint8_t c);

  void clearDisplay(void);
  void invertDisplay(uint8_t i);
  void display();

  /*void startscrollright(uint8_t start, uint8_t stop);
  void startscrollleft(uint8_t start, uint8_t stop);

  void startscrolldiagright(uint8_t start, uint8_t stop);
  void startscrolldiagleft(uint8_t start, uint8_t stop);
  void stopscroll(void); */
  
  void dim(uint8_t contrast);

  void drawPixel(int16_t x, int16_t y, uint16_t color);

  virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
  virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);

 private:
  int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs;
  void fastSPIwrite(uint8_t c);

  boolean hwSPI;
  PortReg *mosiport, *clkport, *csport, *dcport;
  PortMask mosipinmask, clkpinmask, cspinmask, dcpinmask;

  inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline));
  inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline));

};

Please note this line from the .cpp file of this library:

// initializer for I2C - we only indicate the reset pin!
Adafruit_SH1106::Adafruit_SH1106(int8_t reset) :
Adafruit_GFX(SH1106_LCDWIDTH, SH1106_LCDHEIGHT) {
  sclk = dc = cs = sid = -1;
  rst = reset;
}

As opposed to the SSD1306 library, from which this is adapted, where you must make the same declaration like this:

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET);

Does this illustrate my problem?

Don't use Wire.send() or Wire.receive(). I call that: common mistake number 5.

It is possible to get the *.h and *.cpp files of a library and put them in your own project folder. Then you can replace all the "Wire" with "Wire1".

However, I think that is not your problem. Have you heard about the XY-problem ?
How can a device occupy the I2C bus ? Can you try to explain why you think that ?
Which Arduino or Teensy board do you use ?
I think there can be only one Wire library active at a time.
Does that library support software-I2C or software-SPI ?

Thank you for your answer. I did not know about common mistake number 5, nor did I know the XY problem, which is very relatable. In case that is the situation, let me back up and illustrate my issue all the way.

My current (working) setup has the aforementioned Adafruit Trellis on i2c port 1. On i2c port 2, I currently have a generic SSD1306, and I am using the Adafruit_SSD1306 library. Both work perfectly fine, and now I want to put my larger SH1106 where the SSD1306 was, and use the Adafruit_SH1106 library. This library is unofficial, and was made by adapting the SSD1306 library, with certain differences.

In the SSD1306 library (the one that I’m currently using, which works), this is how you declare the class, sorry if that’s the wrong term:

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET);

Note the &Wire1 in there. Works great for me, and this is all that I have to do.

The way that the user designed the Adafruit_SH1106 library, you only declare the OLED reset pin, not the screen width, screen height, or “&Wire”. This line is from the example sketch, which is essentially the exact same as the Adafruit_SSD1306 example sketch:

Adafruit_SH1106 display(OLED_RESET);

I searched the example sketch, and could not find “&Wire” anywhere, so I went into the library to see if I could either find “&Wire”, or if not, if I could find out how to instruct the code to use i2c port 2 instead. I am still very much a beginner to coding, so I wasn’t able to figure it out, so I came here to ask.

Here is everything from the SH1106 example code, up until void setup():

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>

#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2


#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

#if (SH1106_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SH1106.h!");
#endif

here is everything from the Adafruit SSD1306 example code, until void setup()

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.