Ускорение работы библиотеки Adafruit_SSD1306
#1
Делая беспроводной модуль для Квант WiFi  столкнулся с очень медленным выводом на дисплей SSD1306, разобравшись понял что дело в том что даже если рисуешь одну точку или один символ и потом вызываешь функцию display(); чтобы вывести на экран то происходит обновление всего экрана, а это передача по i2c  целых 1024 байт! это минимум 28 а максимум 43 мс, зависит от настроек скорости i2c. Меня это категорически не устраивало так как у меня данные поступали каждые 12мс и их надо обрабатывать и выводить на экран в режиме реального времени.
Я начал искать функцию которая обновляет только ту область экрана которую меняешь, но её нет в библиотеке Adafruit_SSD1306. Думал уже заказывать SPI дисплей, он быстрее но всё равно не так как хотелось-бы, да и не наш это метод, дожать то что есть (i2c) показалось мне интересной задачей. Ну и вот написал я функцию которая позволяет обновлять только ту область экрана которую меняешь, это позволило мне уложится в 12 мс, может кому пригодится.
Вот пример вывода одной строки  стандартной функцией(43мс) и модифицированной (11 мс).
   
Новая функция вставляется в файл Adafruit_SSD1306.cpp
Заголовочная в Adafruit_SSD1306.h
Я вставил рядом с стандартной функцией.
Все это должно быть в папке Adafruit_SSD1306-master которая там где у вас установлены библиотеки.


Это вставляем в Adafruit_SSD1306.cpp
Код:
void Adafruit_SSD1306::display(uint8_t Page_start, uint8_t Page_end, uint8_t Column_start, uint8_t Column_end) {
TRANSACTION_START

static uint8_t  dlist1[] = {
      SSD1306_PAGEADDR,
      0,                      // Page start address
      0,                   // Page end (not really, but works here)
      SSD1306_COLUMNADDR, 0, 0}; // Column start address

dlist1[1] = Page_start;
dlist1[2] = Page_end;
dlist1[4] = Column_start;
dlist1[5] = Column_end;
   
uint8_t n =  sizeof(dlist1);
uint8_t *ptr = dlist1;
if (wire)
   {  
     wire->beginTransmission(i2caddr);
     WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0
     while (n--)WIRE_WRITE(*ptr++);               
     wire->endTransmission();  
   }
  else // SPI -- transaction started in calling function
   {
     SSD1306_MODE_COMMAND
     while (n--) SPIwrite(*ptr++);    
   }

#if defined(ESP8266)
  yield();
#endif

  uint16_t bytesOut;
if (wire) // I2C
   {
    wire->beginTransmission(i2caddr);
    WIRE_WRITE((uint8_t)0x40);
    bytesOut = 1;
   } else {SSD1306_MODE_DATA}
 
  for (int i = Page_start; i <=Page_end; i++)
  {
    ptr = buffer + (i * 128 + Column_start);
    uint16_t count = Column_end-Column_start+1;
    while (count--)
     {
      if (bytesOut >= WIRE_MAX && wire)
        {
         wire->endTransmission();
         wire->beginTransmission(i2caddr);
         WIRE_WRITE((uint8_t)0x40);
         bytesOut = 1;
        }   
       if(wire){ WIRE_WRITE(*ptr++); bytesOut++;}
       else SPIwrite(*ptr++);
     }
   }        
if(wire)wire->endTransmission();

//TRANSACTION_END
#if defined(ESP8266)
  yield();
#endif
}

Это вставляем в Adafruit_SSD1306.h
Код:
void display(uint8_t Page_start, uint8_t Page_end, uint8_t Column_start, uint8_t Column_end);

Page_start,  Page_end значения 0...7, это стоки которые надо обновить.

Column_start, Column_end значения 0....127, это кусок строки который надо обновить.


Пример:
Код:
#include <Adafruit_SSD1306.h>
#define SSD1306_NO_SPLASH
Adafruit_SSD1306 display(128, 64, &Wire, -1);//

uint32_t startTime, leadTime;

void setup()
{
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setFont();
 
  startTime = millis();
  display.setCursor(0,0); 
  display.print("SSD1306 speed test 1");
  display.display();
  leadTime = millis() - startTime;
  Serial.print("SSD1306 speed test 1: ");
  Serial.print(leadTime);
  Serial.println(" ms");
 
  Serial.println();
 
  startTime = millis();
  display.setCursor(0,8); 
  display.print("SSD1306 speed test 2");
  display.display(1,1,0,127);
  leadTime = millis() - startTime;
  Serial.print("SSD1306 speed test 2: ");
  Serial.print(leadTime);
  Serial.println(" ms");
  
}

void loop()
{

}

Есть ограничения, связано это с устройством экранной памяти дисплея. Обновлять можно только по строкам, несколько или одну, всего 8 строк шириной 8 пикселей и длинной 128 пикселей, а вот область строки можно выбирать с точностью до пикселя. Всё это надо учитывать когда размещаешь текст или изображение.
#2
Точнее - я не написал а модифицировал стандартную функцию display();
#3
Можно просто задать начальную строку (0-7) и позицию (0-127) и "пулять" данные,будет быстрее чем задание окна
Правда в ардуино я пень,но на баском авр работает ,и не занимает много места срам