NanoTerminal. Часть 3. OLED-дисплей на чипе SSD1306. Общее описание.

1306
Как и обещал, начинаю публиковать серию статей по работе с OLED-дисплеем на базе чипа SSD1306 разрешением 128 на 64 пикселя. Хотя практически всё нижеописанное будет относиться и к дисплеям с другим разрешением. Datasheet SSD1306 позволяет управлять через параллельный интерфейс 8080, последовательные интерфейсы I2C и SPI. Самыми дешевыми, простыми в освоении, хотя и наиболее тормозными являются версия c I2C-интерфейсом, но для использования в составе терминала — то, что нужно, если конечно мультики на экране не смотреть.

Как видно из картинки (которую я украл на просторах интернета), у рассматриваемого дисплея управление происходит по двум проводам — SDA (данные) и SCL (такт). Это самый распространенный вариант дисплея и самый демократичный — его цена около 170 рублей (2.5 — 3 $). Преимущества и недостатки кратко описаны в соответствующей табличке, но самый главный недостаток — очень хрупкое исполнение. Стекло дисплея неполностью прилегает к плате из стеклотекстолита, большой участок стекла — шириной более 5 мм (на фото —  нижняя прозрачная часть) просто «висит» в воздухе, что при малейшем надавливании приводит к излому. А излом приводит к разрыву внутренних проводников, что в свою очередь выводит из строя часть сегментов экрана.

Преимущества

Недостатки

— отличная контрастность
— невысокая цена за вариант 0.96 дюймов
— простота управления
— множество способов управления
— возможность управлять через I2C, то есть всего по двум проводам
-УЖАСНО хрупкая конструкция
-небольшие размеры, хотя иногда это можно отнести к преимуществам
-высокая цена за размеры отличные от 0.96 дюймов
-относительно невысокий FPS через I2C

Существуют модификации с одноцветными OLED-пикселями, например, белыми, голубыми, желтыми или даже зелеными. Также имеются двухцветные дисплеи, самый распространенный из который синий с желтой полоской, шириной 16 пикселей сверху.


Ну вот в целом и всё, что можно сказать о конструктиве дисплея. Самое время перейти к внутреннему устройству и основам управления. Основными составляющими SSD1306 являются:
— MCU Interface — блок взаимодействия SSD1306 с микроконтроллерами. Воспринимает команды по одному из четырех интерфейсов — параллельный, последовательные 4-wire SPI, 3-wire SPI, 2-wire I2C, транслируют их в единообразном формате в блок обработки команд — Command Decoder. Через MCU Interface также поступают данные, которые транслируются в блок памяти.
— GDDRAM — блок памяти графических данных дисплея (Graphic Display Data RAM). Собственно внутренний буфер SSD1306, в котором хранятся состояния каждого из пикселей дисплея. Путём записи данных в данный блок мы управляем картинкой на экране.
— Display Controller — блок управления экраном. Читает данные из GDDRAM и отображает эту информации на экране в режиме динамической индикации.
Есть и еще несколько блоков , полная картинка есть в datasheet‘e на странице №7.

Нас интересуют в основном два блока — GDDRAM и Command Decoder. Именно с ними происходит всё общение программиста. Причем неважно каким образом Вы направите данные в эти блоки — MCU Interface всё скушает и направит по правильному адресу. Соответственно для управления SSD1306 нужно всего лишь направлять нужные команды и нужные данные. Мы будем эти данные направлять через двухпроводной интерфейс I2C и для этого нужно две базовых функции — для данных (sendData) и для команд (sendCommand). Они практически ничем не отличаются, разница лишь в том, что перед отправкой данных мы шлем в шину I2C значение 0x40, а перед отправкой команды — 0x80, а MCU Interface распознает эти значения и решает куда направить следующий байт.  Иначе говоря, управление дисплеем сводится к отправке последовательностей двухбайтовых комбинаций по адресу SSD1306 равному 0x3C.

#include "Wire.h" 
#define SSD1306_Address               0x3C
#define SSD1306_Command_Mode          0x80
#define SSD1306_Data_Mode             0x40

void sendCommand(unsigned char command)
{
  Wire.beginTransmission(SSD1306_Address);
  Wire.write(SSD1306_Command_Mode);
  Wire.write(command);
  Wire.endTransmission();
}

void sendData(unsigned char Data)
{
     Wire.beginTransmission(SSD1306_Address);
     Wire.write(SSD1306_Data_Mode);
     Wire.write(Data);
     Wire.endTransmission();
}

На этом общая информация заканчивается. Далее мы рассмотрим инициализацию дисплея.