Skip to content

Add 2nd HW I2C support #292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ The library supports different protocols to access the OLED display. Currently t
SSD1306Wire display(0x3c, SDA, SCL); // ADDRESS, SDA, SCL
// for 128x32 displays:
// SSD1306Wire display(0x3c, SDA, SCL, GEOMETRY_128_32); // ADDRESS, SDA, SCL, GEOMETRY_128_32 (or 128_64)
// for using 2nd Hardware I2C (if available)
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_TWO); //default value is I2C_ONE if not mentioned
// By default SD1306Wire set I2C frequency to 700000, you can use set either another frequency or skip setting the frequency by providing -1 value
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, 400000); //set I2C frequency to 400kHz
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, -1); //skip setting the I2C bus frequency
```

for a SH1106:
Expand All @@ -84,6 +89,9 @@ for a SH1106:
#include "SH1106Wire.h"

SH1106Wire display(0x3c, SDA, SCL); // ADDRESS, SDA, SCL
// By default SH1106Wire set I2C frequency to 700000, you can use set either another frequency or skip setting the frequency by providing -1 value
// SH1106Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, 400000); //set I2C frequency to 400kHz
// SH1106Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, -1); //skip setting the I2C bus frequency
```

### I2C with brzo_i2c
Expand Down
5 changes: 5 additions & 0 deletions src/OLEDDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ enum OLEDDISPLAY_GEOMETRY {
GEOMETRY_RAWMODE,
};

enum HW_I2C {
I2C_ONE,
I2C_TWO
};

typedef char (*FontTableLookupFunction)(const uint8_t ch);
char DefaultFontTableLookup(const uint8_t ch);

Expand Down
64 changes: 45 additions & 19 deletions src/SH1106Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,47 @@ class SH1106Wire : public OLEDDisplay {
uint8_t _sda;
uint8_t _scl;
bool _doI2cAutoInit = false;
TwoWire* _wire = NULL;
int _frequency;

public:
SH1106Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64) {
/**
* Create and initialize the Display using Wire library
*
* Beware for retro-compatibility default values are provided for all parameters see below.
* Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to
* ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple
* device on the same bus.
*
* @param _address I2C Display address
* @param _sda I2C SDA pin number, default to -1 to skip Wire begin call
* @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call)
* @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options
* @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE
* @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode
*/
SH1106Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) {
setGeometry(g);

this->_address = _address;
this->_sda = _sda;
this->_scl = _scl;
this->_wire = (_i2cBus==I2C_ONE)?&Wire:&Wire1;
this->_frequency = _frequency;
}

bool connect() {
Wire.begin(this->_sda, this->_scl);
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH8266)
_wire->begin();
#else
// On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us.
if(this->_sda != -1)
_wire->begin(this->_sda, this->_scl);
#endif
// Let's use ~700khz if ESP8266 is in 160Mhz mode
// this will be limited to ~400khz if the ESP8266 in 80Mhz mode.
Wire.setClock(700000);
if(this->_frequency != -1)
_wire->setClock(this->_frequency);
return true;
}

Expand Down Expand Up @@ -107,25 +133,25 @@ class SH1106Wire : public OLEDDisplay {
sendCommand(minBoundXp2L);
for (x = minBoundX; x <= maxBoundX; x++) {
if (k == 0) {
Wire.beginTransmission(_address);
Wire.write(0x40);
_wire->beginTransmission(_address);
_wire->write(0x40);
}
Wire.write(buffer[x + y * displayWidth]);
_wire->write(buffer[x + y * displayWidth]);
k++;
if (k == 16) {
Wire.endTransmission();
_wire->endTransmission();
k = 0;
}
}
if (k != 0) {
Wire.endTransmission();
_wire->endTransmission();
k = 0;
}
yield();
}

if (k != 0) {
Wire.endTransmission();
_wire->endTransmission();
}
#else
uint8_t * p = &buffer[0];
Expand All @@ -134,12 +160,12 @@ class SH1106Wire : public OLEDDisplay {
sendCommand(0x02);
sendCommand(0x10);
for( uint8_t x=0; x<8; x++) {
Wire.beginTransmission(_address);
Wire.write(0x40);
_wire->beginTransmission(_address);
_wire->write(0x40);
for (uint8_t k = 0; k < 16; k++) {
Wire.write(*p++);
_wire->write(*p++);
}
Wire.endTransmission();
_wire->endTransmission();
}
}
#endif
Expand All @@ -154,18 +180,18 @@ class SH1106Wire : public OLEDDisplay {
return 0;
}
inline void sendCommand(uint8_t command) __attribute__((always_inline)){
Wire.beginTransmission(_address);
Wire.write(0x80);
Wire.write(command);
Wire.endTransmission();
_wire->beginTransmission(_address);
_wire->write(0x80);
_wire->write(command);
_wire->endTransmission();
}

void initI2cIfNeccesary() {
if (_doI2cAutoInit) {
#ifdef ARDUINO_ARCH_AVR
Wire.begin();
_wire->begin();
#else
Wire.begin(this->_sda, this->_scl);
_wire->begin(this->_sda, this->_scl);
#endif
}
}
Expand Down
60 changes: 41 additions & 19 deletions src/SSD1306Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,56 @@
#define _min min
#define _max max
#endif
//--------------------------------------

class SSD1306Wire : public OLEDDisplay {
private:
uint8_t _address;
int _sda;
int _scl;
bool _doI2cAutoInit = false;
TwoWire* _wire = NULL;
int _frequency;

public:
SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64) {

/**
* Create and initialize the Display using Wire library
*
* Beware for retro-compatibility default values are provided for all parameters see below.
* Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to
* ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple
* device on the same bus.
*
* @param _address I2C Display address
* @param _sda I2C SDA pin number, default to -1 to skip Wire begin call
* @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call)
* @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options
* @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE
* @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode
*/
SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) {
setGeometry(g);

this->_address = _address;
this->_sda = _sda;
this->_scl = _scl;
this->_wire = (_i2cBus==I2C_ONE)?&Wire:&Wire1;
this->_frequency = _frequency;
}

bool connect() {
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH8266)
Wire.begin();
_wire->begin();
#else
// On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us.
if(this->_sda != -1)
Wire.begin(this->_sda, this->_scl);
_wire->begin(this->_sda, this->_scl);
#endif
// Let's use ~700khz if ESP8266 is in 160Mhz mode
// this will be limited to ~400khz if the ESP8266 in 80Mhz mode.
Wire.setClock(700000);
if(this->_frequency != -1)
_wire->setClock(this->_frequency);
return true;
}

Expand Down Expand Up @@ -115,22 +137,22 @@ class SSD1306Wire : public OLEDDisplay {
for (y = minBoundY; y <= maxBoundY; y++) {
for (x = minBoundX; x <= maxBoundX; x++) {
if (k == 0) {
Wire.beginTransmission(_address);
Wire.write(0x40);
_wire->beginTransmission(_address);
_wire->write(0x40);
}

Wire.write(buffer[x + y * this->width()]);
_wire->write(buffer[x + y * this->width()]);
k++;
if (k == 16) {
Wire.endTransmission();
_wire->endTransmission();
k = 0;
}
}
yield();
}

if (k != 0) {
Wire.endTransmission();
_wire->endTransmission();
}
#else

Expand All @@ -148,14 +170,14 @@ class SSD1306Wire : public OLEDDisplay {
}

for (uint16_t i=0; i < displayBufferSize; i++) {
Wire.beginTransmission(this->_address);
Wire.write(0x40);
_wire->beginTransmission(this->_address);
_wire->write(0x40);
for (uint8_t x = 0; x < 16; x++) {
Wire.write(buffer[i]);
_wire->write(buffer[i]);
i++;
}
i--;
Wire.endTransmission();
_wire->endTransmission();
}
#endif
}
Expand All @@ -170,18 +192,18 @@ class SSD1306Wire : public OLEDDisplay {
}
inline void sendCommand(uint8_t command) __attribute__((always_inline)){
initI2cIfNeccesary();
Wire.beginTransmission(_address);
Wire.write(0x80);
Wire.write(command);
Wire.endTransmission();
_wire->beginTransmission(_address);
_wire->write(0x80);
_wire->write(command);
_wire->endTransmission();
}

void initI2cIfNeccesary() {
if (_doI2cAutoInit) {
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH8266)
Wire.begin();
_wire->begin();
#else
Wire.begin(this->_sda, this->_scl);
_wire->begin(this->_sda, this->_scl);
#endif
}
}
Expand Down