Драйвер для SSD1306

gppsoft
Offline
Зарегистрирован: 13.10.2014

Парни. Написал драйвер для популярного LED дисплея на конроллере SSD1306.  Может кому-нибудь пригодится кроме меня? Данный драйвер использует минимум ОЗУ. Для буфера можно использовать от 128 до 1024 байт. Можно использовать даже с  attiny85. Прошу помочь оптимизировать код. Так как на С++ я пишу не часто, то приветствуется здоровая и не здоровая критика с примерами "как надо". Буду благодарен всем, кто допишет новые методы для рисования примитивов. К примеру окружности, треугольника и т.д. На данный момент драйвер поддерживает вывод текста и отрисовку битмапов.  Выводить можно в любое место на экране. Простенький шрифт(5x8) с поддержкой кирилицы уже "вшит" в драйвер. Единственное чего нужно придерживаться, это цикла перерисовки экрана. Вообщем навеяно этим и этим. Заранее огромное спасибо!

Проект c примером для Atmel Studio 6.

 

 

Logik
Offline
Зарегистрирован: 05.08.2014

Круги помнится долго оптимизировал. Вышло так

void SSD1306Graphic::drawCircleHelper(byte x0, byte y0, byte r, byte cornername, byte operation) 
{
  char f = 1 - r;
  char ddF_x = 1;
  char ddF_y = -2 * r;
  char x = 0;
  char y = r;


  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    if (cornername & 0x4) {
      Pixel(x0 + x, y0 + y);
      Pixel(x0 + y, y0 + x);
    } 
    if (cornername & 0x2) {
      Pixel(x0 + x, y0 - y);
      Pixel(x0 + y, y0 - x);
    }
    if (cornername & 0x8) {
      Pixel(x0 - y, y0 + x);
      Pixel(x0 - x, y0 + y);
    }
    if (cornername & 0x1) {
      Pixel(x0 - y, y0 - x);
      Pixel(x0 - x, y0 - y);
    }
  }
}
void SSD1306Graphic::drawCircle(byte x0, byte y0, byte r, byte operation)
{
    Pixel(x0, y0+r);
    Pixel(x0, y0-r);
    Pixel(x0+r, y0);
    Pixel(x0-r, y0);

    drawCircleHelper(x0, y0, r, 0xF, operation);
}

Функция Pixel должна проверять попадаем в область для которой задан буфер или нет. У меня буфер (он же канва по сути) задается отдельной функцией вместе с координатами при начале операции и освобождается после вывода на экран.

Скорость вывода на экран можете поднять, он выше 800КГц тянет.

Готовтесь добавлять шрифты, много и крупные, базовый слишком мелок.

Еще из интересного прокрутки.

// Scrolling Commands
#define SSD1306_HORIZONTAL_SCROLL_RIGHT					0x26
#define SSD1306_HORIZONTAL_SCROLL_LEFT					0x27
#define SSD1306_HORIZONTAL_SCROLL_VERTICAL_AND_RIGHT	0x29
#define SSD1306_HORIZONTAL_SCROLL_VERTICAL_AND_LEFT		0x2A
#define SSD1306_DEACTIVATE_SCROLL						0x2E
#define SSD1306_ACTIVATE_SCROLL							0x2F
#define SSD1306_SET_VERTICAL_SCROLL_AREA				0xA3


void SSD1306::Scroll(byte right, byte speed, byte Page, byte Pages, byte Voffset)
{
    byte command;

    if (Voffset)
        command= SSD1306_HORIZONTAL_SCROLL_VERTICAL_AND_RIGHT;
    else
       command= SSD1306_HORIZONTAL_SCROLL_RIGHT;

    if (!right)
        command++;

    sendTWIcommandCnt(command);
    writeByte(0);
    writeByte(Page);
    writeByte(speed);
    writeByte(Page+Pages-1);
    writeByte(Voffset);
    if (!(command&0x08)) //горизонтальный только
    {
        writeByte(0xff);
    }
    sendStop();

}
void SSD1306::SetVScrollArray(byte x, byte w)
{
    sendTWIcommand(SSD1306_SET_VERTICAL_SCROLL_AREA);
    sendTWIcommand(x);
    sendTWIcommand(w);
    sendStop();

}
void SSD1306::ScrollActivate(byte go)
{
    if (go)
        sendTWIcommand(SSD1306_ACTIVATE_SCROLL);
    else
        sendTWIcommand(SSD1306_DEACTIVATE_SCROLL);
}

Цепляйте себе, может чё интересное и выйдет.

gppsoft
Offline
Зарегистрирован: 13.10.2014

Спасибо. Как я понимаю это часть вашего драйвера? Можно ли увидеть его целиком?

gppsoft
Offline
Зарегистрирован: 13.10.2014

Что за параметр cornername?

gppsoft
Offline
Зарегистрирован: 13.10.2014

Вообщем ваша функция "в лоб" не заработала. Рисует наклоненный квадрат :) 

Logik
Offline
Зарегистрирован: 05.08.2014

cornername определяет маску четвертей круга. Странно что не заработала, щас проверю.

Проверил. Так работает.

  byte c[40*3];
  memset(c, 0, sizeof(c));
  myOLED.InitFrame(20, 2, 40, 3, c);
  myOLED.drawLine(0,0,20,10,1);
  myOLED.drawCircle(20,10,10,1);
  myOLED.drawCircle(20,10,15,1);
  myOLED.update();

линию рисует и две окружности. Вторая вылазит за пределы окна и обрезается сверху и снизу.

С какими параметрами вызов у Вас. Может слишком большие числа? Там все оптимизировано под байт, т.к. размеры экрана соответствующие.

gppsoft
Offline
Зарегистрирован: 13.10.2014

Вот что получается. Еще я не понял что за неиспользуемая переменная "operation"?

Logik
Offline
Зарегистрирован: 05.08.2014

С какими параметрами вызов у Вас? Может эмуль кривой. operation задает режим вывода - зажечь пиксель, потушить или инвертировать. Картинка для кода из выше.

Logik
Offline
Зарегистрирован: 05.08.2014

Похоже что дело в char. Студия похоже считает его unsigned по умолчанию. Укажите явно signed char в обявлении в функции которую я выкладывал.

Заодно глянул чего operation передается в функцию рисования круга и не передается дальше. А ХЗ ))). 

Вывод пикселя его принимает как необязательный и если не передан, то считает что пиксель нужно зажечь.  Очевидно что такого для моих проектов достаточно, вот нигде проблема и не выявилась. По хорошему его надо 3-м параметром в Pixel передавать.

Вот собственно и  нарисовался ответ на вопрос о публикации библиотеки. Библиотека  - штука куда более серезная чем просто кусок кода заработавшего у меня. Она требует большого обёма тестирования, много больше чем требуется для моих проектов. И на разных платформах и с разными версиями железа и компилятора. У меня нет ни желания ни необходимости это делать.  А не сделав это код остается сырым с скрытыми ошибками. Но в моих проектах работает - меня устраивает. Мои проекты для меня приоритетней чем сомнительная известность "тот самый что делал либу". Опубликовав "как есть" прийдется постоянно реагировать на фидбеки или смирится что у многих так и не работает (тогда смыслу выкладывать??). Ситуация усугубляется тем, что одной либой не ограничивается, например вывод по I2C у меня тоже на своей либе. 

Кстати Ваш экран каким интерфейсом подключен? Судя по картинке эмуля там интересно...

gppsoft
Offline
Зарегистрирован: 13.10.2014

Logik пишет:

Похоже что дело в char. Студия похоже считает его unsigned по умолчанию. Укажите явно signed char в обявлении в функции которую я выкладывал.

Заодно глянул чего operation передается в функцию рисования круга и не передается дальше. А ХЗ ))). 

Вывод пикселя его принимает как необязательный и если не передан, то считает что пиксель нужно зажечь.  Очевидно что такого для моих проектов достаточно, вот нигде проблема и не выявилась. По хорошему его надо 3-м параметром в Pixel передавать.

Вот собственно и  нарисовался ответ на вопрос о публикации библиотеки. Библиотека  - штука куда более серезная чем просто кусок кода заработавшего у меня. Она требует большого обёма тестирования, много больше чем требуется для моих проектов. И на разных платформах и с разными версиями железа и компилятора. У меня нет ни желания ни необходимости это делать.  А не сделав это код остается сырым с скрытыми ошибками. Но в моих проектах работает - меня устраивает. Мои проекты для меня приоритетней чем сомнительная известность "тот самый что делал либу". Опубликовав "как есть" прийдется постоянно реагировать на фидбеки или смирится что у многих так и не работает (тогда смыслу выкладывать??). Ситуация усугубляется тем, что одной либой не ограничивается, например вывод по I2C у меня тоже на своей либе. 

Кстати Ваш экран каким интерфейсом подключен? Судя по картинке эмуля там интересно...

Экран подключен по i2c. На устройстве такая же проблема, эмулятор тут не причем. Посмотрите мой код в первом сообщении.

Logik
Offline
Зарегистрирован: 05.08.2014

Делайте явный signed char, пишите как вызываете функцию, попробую у себя. 

А чего на картинке эмуля подключено не i2c? Вроде как паралельная шина..

gppsoft
Offline
Зарегистрирован: 13.10.2014

Logik пишет:

Делайте явный signed char, пишите как вызываете функцию, попробую у себя. 

А чего на картинке эмуля подключено не i2c? Вроде как паралельная шина..

Обязательно проверю, как буду у ПК. Там i2c, просто для работы данного дисплея необходимо сделать минимальную обвязку. Вы можете выложить код своей библиотеки на "поковыряться"? Спасибо за ответы.

gppsoft
Offline
Зарегистрирован: 13.10.2014

Logik пишет:

Делайте явный signed char, пишите как вызываете функцию, попробую у себя. 

Ошибка была в том, что я использовал uint8_t. Сейчас все в норме.