From 24e44fc82bdacb75efaede6963fbe3df7b7390eb Mon Sep 17 00:00:00 2001 From: Fabrice Weinberg <Fabrice@weinberg.me> Date: Thu, 26 May 2016 13:40:26 +0200 Subject: [PATCH] Add optional support for using brzo as i2c lib See https://github.com/pasko-zh/brzo_i2c for more info about the library. It is very fast and can run the OLED at 120fps even in 80Mhz mode. --- SSD1306.cpp | 218 ++++++++++++++++++++++++++++++++-------------------- SSD1306.h | 16 +++- 2 files changed, 148 insertions(+), 86 deletions(-) diff --git a/SSD1306.cpp b/SSD1306.cpp index 6f29054..e5e39c1 100644 --- a/SSD1306.cpp +++ b/SSD1306.cpp @@ -50,14 +50,8 @@ bool SSD1306::init() { } #endif - Wire.begin(this->sda, this->sdc); - - // 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); - + reconnect(); sendInitCommands(); - resetDisplay(); return true; @@ -72,14 +66,15 @@ void SSD1306::end() { void SSD1306::resetDisplay(void) { clear(); - #ifdef SSD1306_DOUBLE_BUFFER - memset(buffer_back, 1, DISPLAY_BUFFER_SIZE); - #endif display(); } void SSD1306::reconnect() { - Wire.begin(this->sda, this->sdc); + #ifdef SSD1306_USE_BRZO + brzo_i2c_setup(this->sda, this->sdc, 2000); + #else + Wire.begin(this->sda, this->sdc); + #endif } void SSD1306::setColor(SSD1306_COLOR color) { @@ -518,100 +513,155 @@ void SSD1306::flipScreenVertically() { void SSD1306::display(void) { #ifdef SSD1306_DOUBLE_BUFFER - uint16_t minBoundY = 8; - uint16_t maxBoundY = 0; - - uint16_t minBoundX = 129; - uint16_t maxBoundX = 0; - - uint16_t x, y; - - // Calculate the Y bounding box of changes - // and copy buffer[pos] to buffer_back[pos]; - for (y = 0; y < 8; y++) { - for (x = 0; x < DISPLAY_WIDTH; x++) { - uint16_t pos = x + y * DISPLAY_WIDTH; - if (buffer[pos] != buffer_back[pos]) { - minBoundY = min(minBoundY, y); - maxBoundY = max(maxBoundY, y); - minBoundX = min(minBoundX, x); - maxBoundX = max(maxBoundX, x); - } - buffer_back[pos] = buffer[pos]; + uint16_t minBoundY = ~0; + uint16_t maxBoundY = 0; + + uint16_t minBoundX = ~0; + uint16_t maxBoundX = 0; + + uint16_t x, y; + + // Calculate the Y bounding box of changes + // and copy buffer[pos] to buffer_back[pos]; + for (y = 0; y < 8; y++) { + for (x = 0; x < DISPLAY_WIDTH; x++) { + uint16_t pos = x + y * DISPLAY_WIDTH; + if (buffer[pos] != buffer_back[pos]) { + minBoundY = min(minBoundY, y); + maxBoundY = max(maxBoundY, y); + minBoundX = min(minBoundX, x); + maxBoundX = max(maxBoundX, x); + } + buffer_back[pos] = buffer[pos]; + } + yield(); } - yield(); - } - // If the minBoundY wasn't updated - // we can savely assume that buffer_back[pos] == buffer[pos] - // holdes true for all values of pos - if (minBoundY == 8) return; - - sendCommand(COLUMNADDR); - sendCommand(minBoundX); - sendCommand(maxBoundX); - - sendCommand(PAGEADDR); - sendCommand(minBoundY); - sendCommand(maxBoundY); - - byte k = 0; - for (y = minBoundY; y <= maxBoundY; y++) { - for (x = minBoundX; x <= maxBoundX; x++) { - if (k == 0) { - Wire.beginTransmission(this->i2cAddress); - Wire.write(0x40); + // If the minBoundY wasn't updated + // we can savely assume that buffer_back[pos] == buffer[pos] + // holdes true for all values of pos + if (minBoundY == ~0) return; + + sendCommand(COLUMNADDR); + sendCommand(minBoundX); + sendCommand(maxBoundX); + + sendCommand(PAGEADDR); + sendCommand(minBoundY); + sendCommand(maxBoundY); + + byte k = 0; + #ifdef SSD1306_USE_BRZO + uint8_t sendBuffer[17]; + sendBuffer[0] = 0x40; + brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED); + for (y = minBoundY; y <= maxBoundY; y++) { + for (x = minBoundX; x <= maxBoundX; x++) { + k++; + sendBuffer[k] = buffer[x + y * DISPLAY_WIDTH]; + if (k == 16) { + brzo_i2c_write(sendBuffer, 17, true); + k = 0; + } } - Wire.write(buffer[x + y * DISPLAY_WIDTH]); - k++; - if (k == 16) { - Wire.endTransmission(); - k = 0; + yield(); + } + brzo_i2c_write(sendBuffer, k + 1, true); + brzo_i2c_end_transaction(); + #else + for (y = minBoundY; y <= maxBoundY; y++) { + for (x = minBoundX; x <= maxBoundX; x++) { + if (k == 0) { + Wire.beginTransmission(this->i2cAddress); + Wire.write(0x40); + } + Wire.write(buffer[x + y * DISPLAY_WIDTH]); + k++; + if (k == 16) { + Wire.endTransmission(); + k = 0; + } } + yield(); } - yield(); - } - if (k != 0) { - Wire.endTransmission(); - } + if (k != 0) { + Wire.endTransmission(); + } + #endif #else // No double buffering - sendCommand(COLUMNADDR); - sendCommand(0x0); - sendCommand(0x7F); - - sendCommand(PAGEADDR); - sendCommand(0x0); - sendCommand(0x7); - - for (uint16_t i=0; i < DISPLAY_BUFFER_SIZE; i++) { - Wire.beginTransmission(this->i2cAddress); - Wire.write(0x40); - for (uint8_t x = 0; x < 16; x++) { - Wire.write(buffer[i]); - i++; - } - i--; - Wire.endTransmission(); - } + sendCommand(COLUMNADDR); + sendCommand(0x0); + sendCommand(0x7F); + + sendCommand(PAGEADDR); + sendCommand(0x0); + sendCommand(0x7); + + #ifdef SSD1306_USE_BRZO + uint8_t sendBuffer[17]; + sendBuffer[0] = 0x40; + brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED); + for (uint16_t i=0; i<DISPLAY_BUFFER_SIZE; i++) { + for (uint8_t x=1; x<17; x++) { + sendBuffer[x] = buffer[i]; + i++; + } + i--; + brzo_i2c_write(sendBuffer, 17, true); + yield(); + } + brzo_i2c_end_transaction(); + #else + byte k = 0; + for (y = minBoundY; y <= maxBoundY; y++) { + for (x = minBoundX; x <= maxBoundX; x++) { + if (k == 0) { + Wire.beginTransmission(this->i2cAddress); + Wire.write(0x40); + } + Wire.write(buffer[x + y * DISPLAY_WIDTH]); + k++; + if (k == 16) { + Wire.endTransmission(); + k = 0; + } + } + yield(); + } + + if (k != 0) { + Wire.endTransmission(); + } + #endif #endif } void SSD1306::clear(void) { memset(buffer, 0, DISPLAY_BUFFER_SIZE); + #ifdef SSD1306_DOUBLE_BUFFER + memset(buffer_back, 1, DISPLAY_BUFFER_SIZE); + #endif } // Private functions void SSD1306::sendCommand(unsigned char com) { - Wire.beginTransmission(this->i2cAddress); //begin transmitting - Wire.write(0x80); //command mode - Wire.write(com); - Wire.endTransmission(); // stop transmitting + #ifdef SSD1306_USE_BRZO + uint8_t command[2] = {0x80 /* command mode */, com}; + brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED); + brzo_i2c_write(command, 2, true); + brzo_i2c_end_transaction(); + #else + Wire.beginTransmission(this->i2cAddress); //begin transmitting + Wire.write(0x80); //command mode + Wire.write(com); + Wire.endTransmission(); // stop transmitting + #endif } void SSD1306::sendInitCommands(void) { diff --git a/SSD1306.h b/SSD1306.h index 3b878e6..2c4400a 100644 --- a/SSD1306.h +++ b/SSD1306.h @@ -28,10 +28,22 @@ #pragma once #include <Arduino.h> -#include <Wire.h> - #include "SSD1306Fonts.h" +#ifdef SSD1306_USE_BRZO + #include "brzo_i2c.h" + // Brzo can handle 1Mhz in ESP8266 160Mhz mode + // and 800KHz in 80Mhz mode + #if F_CPU == 160000000L + #define BRZO_I2C_SPEED 1000 + #else + #define BRZO_I2C_SPEED 800 + #endif +#else // Default use Wire + #include <Wire.h> +#endif + + //#define DEBUG_SSD1306(...) Serial.printf( __VA_ARGS__ ) #ifndef DEBUG_SSD1306 -- GitLab