To use an SSD1306 I2C Display with Endpoint I have ported the TinyCLR driver (below).
As this display is 1Bpp you will need the TinyCLR BasicGraphics driver, and port it to
namespace GHIElectronics.Endpoint.Drivers.BasicGraphics;
BasicGraphics does not need any modification other than updating the namespace.
SSD1306.cs
using GHIElectronics.Endpoint.Core;
using System.Device.I2c;
namespace GHIElectronics.Endpoint.Drivers.SolomonSystech.SSD1306
{
public class SSD1306Controller
{
private readonly byte[] vram = new byte[128 * 64 / 8 + 1];
private readonly byte[] buffer2 = new byte[2];
private readonly I2cDevice i2cDev;
public int Width => 128;
public int Height => 64;
public SSD1306Controller(int i2cBus)
{
this.vram[0] = 0x40;
EPM815.I2c.Initialize(i2cBus)
I2cConnectionSettings i2cConnectionSetting = new I2cConnectionSettings(i2cBus, 0x3C);
i2cDev = I2cDevice.Create(i2cConnectionSetting);
this.Initialize();
}
private void Initialize()
{
this.SendCommand(0xAE); //turn off oled panel
this.SendCommand(0x00); //set low column address
this.SendCommand(0x10); //set high column address
this.SendCommand(0x40); //set start line address
this.SendCommand(0x81); //set contrast control register
this.SendCommand(0xCF);
this.SendCommand(0xA1); //set segment re-map 95 to 0
this.SendCommand(0xA6); //set normal display
this.SendCommand(0xA8); //set multiplex ratio(1 to 64)
this.SendCommand(0x3F); //1/64 duty
this.SendCommand(0xD3); //set display offset
this.SendCommand(0x00); //not offset
this.SendCommand(0xD5); //set display clock divide ratio/oscillator frequency
this.SendCommand(0x80); //set divide ratio
this.SendCommand(0xD9); //set pre-charge period
this.SendCommand(0xF1);
this.SendCommand(0xDA); //set com pins hardware configuration
this.SendCommand(0x12);
this.SendCommand(0xDB); //set vcomh
this.SendCommand(0x40); //set startline 0x0
this.SendCommand(0x8D); //set Charge Pump enable/disable
this.SendCommand(0x14); //set(0x10) disable
this.SendCommand(0xAF); //turn on oled panel
this.SendCommand(0xC8); //mirror the screen
// Mapping
this.SendCommand(0x20);
this.SendCommand(0x00);
this.SendCommand(0x21);
this.SendCommand(0);
this.SendCommand(128 - 1);
this.SendCommand(0x22);
this.SendCommand(0);
this.SendCommand(7);
}
public void Dispose() => this.i2cDev.Dispose();
private void SendCommand(byte cmd)
{
this.buffer2[1] = cmd;
this.i2cDev.Write(this.buffer2);
}
public void SetColorFormat(bool invert) => this.SendCommand((byte)(invert ? 0xA7 : 0xA6));
//public void SetPixel(int x, int y, bool color) {
// if (x < 0 || y < 0 || x >= this.Width || y >= this.Height) return;
// var index = (y / 8) * this.Width + x;
// if (color) {
// this.vram[1 + index] |= (byte)(1 << (y % 8));
// }
// else {
// this.vram[1 + index] &= (byte)(~(1 << (y % 8)));
// }
//}
//public void DrawBuffer(byte[] buffer) {
// var x = 0;
// var y = 0;
// for (var i = 0; i < buffer.Length; i += 2) {
// var color = (buffer[i + 1] << 8) | (buffer[i]);
// if (color == 0) {
// this.SetPixel(x++, y, false);
// }
// else {
// this.SetPixel(x++, y, true);
// }
// if (x == this.Width) {
// x = 0;
// y++;
// }
// }
// this.i2c.Write(this.vram);
//}
public void DrawBufferNative(byte[] buffer) => this.DrawBufferNative(buffer, 0, buffer.Length);
public void DrawBufferNative(byte[] buffer, int offset, int count)
{
Array.Copy(buffer, offset, this.vram, 1, count);
this.i2cDev.Write(this.vram);
}
}
}
Example:
using GHIElectronics.Endpoint.Core;
using GHIElectronics.Endpoint.Drivers.BasicGraphics;
using GHIElectronics.Endpoint.Drivers.SolomonSystech.SSD1306;
namespace TinyCLROLED
{
internal class Program
{
private static SSD1306Controller OLED;
private const int SCREEN_WIDTH = 128;
private const int SCREEN_HEIGHT = 64;
static void Main()
{
OLED = new SSD1306Controller(EPM815.I2c.I2c6);
var basicGfx = new BasicGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, ColorFormat.OneBpp);
var colorWhite = BasicGraphics.ColorFromRgb(255, 255, 255);
basicGfx.Clear();
basicGfx.DrawString("Hello world!", colorWhite, 5, 5);
basicGfx.DrawString("2nd line.", colorWhite, 5, 20);
basicGfx.DrawTinyString("3rd line.", colorWhite, 5, 35);
OLED.DrawBufferNative(basicGfx.Buffer);
Thread.Sleep(1);
}
}
}