Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
#include "defines.h"
#include "DisplayInterface.h"

// Used for OLED displays. Orientation is not implemented for LCDs, but they share "HALDisplay::create" constructors
enum class Orientation {
normal,
flipped
};

// Allow maximum message length to be overridden from config.h
#if !defined(MAX_MSG_SIZE)
#define MAX_MSG_SIZE 20
Expand Down
21 changes: 15 additions & 6 deletions Display_Implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,21 @@
// LiquidCrystal_I2C for I2C LCD driver for HD44780 with PCF8574 'backpack'.

#if defined(OLED_DRIVER)
#define DISPLAY_START(xxx) { \
DisplayInterface *t = new Display(new SSD1306AsciiWire(OLED_DRIVER)); \
t->begin(); \
xxx; \
t->refresh(); \
}
#if defined(FLIP_OLED)
#define DISPLAY_START(xxx) { \
DisplayInterface *t = new Display(new SSD1306AsciiWire(OLED_DRIVER, Orientation::flipped)); \
t->begin(); \
xxx; \
t->refresh(); \
}
#else
#define DISPLAY_START(xxx) { \
DisplayInterface *t = new Display(new SSD1306AsciiWire(OLED_DRIVER)); \
t->begin(); \
xxx; \
t->refresh(); \
}
#endif

#elif defined(LCD_DRIVER)
#define DISPLAY_START(xxx) { \
Expand Down
12 changes: 6 additions & 6 deletions IO_HALDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ class HALDisplay : public IODevice, public DisplayInterface {

public:
// Static function to handle "HALDisplay::create(...)" calls.
static void create(I2CAddress i2cAddress, int width, int height) {
if (checkNoOverlap(0, 0, i2cAddress)) new HALDisplay(0, i2cAddress, width, height);
static void create(I2CAddress i2cAddress, int width, int height, Orientation orientation = Orientation::normal) {
if (checkNoOverlap(0, 0, i2cAddress)) new HALDisplay(0, i2cAddress, width, height, orientation);
}
static void create(uint8_t displayNo, I2CAddress i2cAddress, int width, int height) {
if (checkNoOverlap(0, 0, i2cAddress)) new HALDisplay(displayNo, i2cAddress, width, height);
static void create(uint8_t displayNo, I2CAddress i2cAddress, int width, int height, Orientation orientation = Orientation::normal) {
if (checkNoOverlap(0, 0, i2cAddress)) new HALDisplay(displayNo, i2cAddress, width, height, orientation);
}

protected:
// Constructor
HALDisplay(uint8_t displayNo, I2CAddress i2cAddress, int width, int height) {
_displayDriver = new T(i2cAddress, width, height);
HALDisplay(uint8_t displayNo, I2CAddress i2cAddress, int width, int height, Orientation orientation) {
_displayDriver = new T(i2cAddress, width, height, orientation);
if (!_displayDriver) return; // Check for memory allocation failure
_I2CAddress = i2cAddress;
_width = width;
Expand Down
2 changes: 1 addition & 1 deletion LiquidCrystal_I2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
// LiquidCrystal constructor is called).

LiquidCrystal_I2C::LiquidCrystal_I2C(I2CAddress lcd_Addr, uint8_t lcd_cols,
uint8_t lcd_rows) {
uint8_t lcd_rows, Orientation orientation) {
_Addr = lcd_Addr;
lcdRows = lcd_rows; // Number of character rows (typically 2 or 4).
lcdCols = lcd_cols; // Number of character columns (typically 16 or 20)
Expand Down
3 changes: 2 additions & 1 deletion LiquidCrystal_I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@

class LiquidCrystal_I2C : public DisplayDevice {
public:
LiquidCrystal_I2C(I2CAddress lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);
// Changing orientation not implemented for LCDs, but provide default parameter for compatibility with other display drivers
LiquidCrystal_I2C(I2CAddress lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows, Orientation orientation = Orientation::normal);
bool begin() override;
void clearNative() override;
void setRowNative(byte line) override;
Expand Down
61 changes: 56 additions & 5 deletions SSD1306Ascii.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,27 @@ const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = {
SSD1306_DISPLAYON
};

const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit_FLIP[] = {
// Init sequence changing SEGREMAP and COMSCAN to flip display orientation
0x00, // Set to command mode
SSD1306_DISPLAYOFF,
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially)
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
SSD1306_SETSTARTLINE | 0x0, // line #0
SSD1306_CHARGEPUMP, 0x14, // internal vcc
SSD1306_MEMORYMODE, 0x02, // page mode
SSD1306_SEGREMAP | 0x0, // column 0 mapped to SEG0
SSD1306_COMSCANINC, // column scan direction normal
SSD1306_SETCOMPINS, 0X12, // set COM pins
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
SSD1306_DISPLAYALLON_RESUME,
SSD1306_NORMALDISPLAY,
SSD1306_DISPLAYON
};

//------------------------------------------------------------------------------
// This section is based on https://github.com/stanleyhuangyc/MultiLCD

Expand All @@ -139,19 +160,41 @@ const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = {
SSD1306_DISPLAYON
};

// Init sequence changing SEGREMAP and COMSCAN to flip display orientation
const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init_FLIP[] = {
0x00, // Set to command mode
SSD1306_DISPLAYOFF,
SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset
SSD1306_SETSTARTPAGE | 0X0, // set page address
SSD1306_SETSTARTLINE | 0x0, // set start line
SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable
SSD1306_SEGREMAP | 0x0, // column 0 mapped to SEG0
SSD1306_COMSCANINC, // column scan direction normal
SSD1306_SETCOMPINS, 0X12, // set COM pins
SSD1306_SETCONTRAST, 0x80, // 128
SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period
SSD1306_SETVCOMDETECT, 0x40, // set vcomh
SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts
SSD1306_NORMALDISPLAY, // normal / reverse
SSD1306_DISPLAYON
};

//==============================================================================
// SSD1306AsciiWire Method Definitions
//------------------------------------------------------------------------------

// Auto-detect address
SSD1306AsciiWire::SSD1306AsciiWire(int width, int height)
: SSD1306AsciiWire(0, width, height) { }
SSD1306AsciiWire::SSD1306AsciiWire(int width, int height, Orientation orientation)
: SSD1306AsciiWire(0, width, height, orientation) { }

// Constructor with explicit address
SSD1306AsciiWire::SSD1306AsciiWire(I2CAddress address, int width, int height) {
SSD1306AsciiWire::SSD1306AsciiWire(I2CAddress address, int width, int height, Orientation orientation) {
m_i2cAddr = address;
m_displayWidth = width;
m_displayHeight = height;
m_orientation = orientation;
// Set size in characters
m_charsPerColumn = m_displayHeight / fontHeight;
m_charsPerRow = (m_displayWidth+fontWidth-1) / fontWidth; // Round up
Expand Down Expand Up @@ -180,10 +223,18 @@ bool SSD1306AsciiWire::begin() {
if (m_displayWidth==132 && m_displayHeight==64) {
// SH1106 display. This uses 128x64 centered within a 132x64 OLED.
m_colOffset = 2;
I2CManager.write_P(m_i2cAddr, SH1106_132x64init, sizeof(SH1106_132x64init));
if (m_orientation == Orientation::flipped) {
I2CManager.write_P(m_i2cAddr, SH1106_132x64init_FLIP, sizeof(SH1106_132x64init_FLIP));
} else {
I2CManager.write_P(m_i2cAddr, SH1106_132x64init, sizeof(SH1106_132x64init));
}
} else if (m_displayWidth==128 && (m_displayHeight==64 || m_displayHeight==32)) {
// SSD1306 or SSD1309 128x64 or 128x32
I2CManager.write_P(m_i2cAddr, Adafruit128xXXinit, sizeof(Adafruit128xXXinit));
if (m_orientation == Orientation::flipped) {
I2CManager.write_P(m_i2cAddr, Adafruit128xXXinit_FLIP, sizeof(Adafruit128xXXinit_FLIP));
} else {
I2CManager.write_P(m_i2cAddr, Adafruit128xXXinit, sizeof(Adafruit128xXXinit));
}
if (m_displayHeight == 32)
I2CManager.write(m_i2cAddr, 5, 0, // Set command mode
SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
Expand Down
10 changes: 7 additions & 3 deletions SSD1306Ascii.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
class SSD1306AsciiWire : public DisplayDevice {
public:

// Constructors
SSD1306AsciiWire(int width, int height); // Auto-detects I2C address
SSD1306AsciiWire(I2CAddress address, int width, int height);
// Constructors; optional orientation paramater defaults to normal
SSD1306AsciiWire(int width, int height, Orientation orientation = Orientation::normal); // Auto-detects I2C address
SSD1306AsciiWire(I2CAddress address, int width, int height, Orientation orientation = Orientation::normal);

// Initialize the display controller.
bool begin();
Expand All @@ -68,6 +68,8 @@ class SSD1306AsciiWire : public DisplayDevice {
uint8_t m_displayWidth;
// Display height.
uint8_t m_displayHeight;
// Rotation of display
Orientation m_orientation;
// Display width in characters
uint8_t m_charsPerRow;
// Display height in characters
Expand Down Expand Up @@ -95,6 +97,8 @@ class SSD1306AsciiWire : public DisplayDevice {
static const uint8_t System6x8[];
static const uint8_t FLASH Adafruit128xXXinit[];
static const uint8_t FLASH SH1106_132x64init[];
static const uint8_t FLASH Adafruit128xXXinit_FLIP[];
static const uint8_t FLASH SH1106_132x64init_FLIP[];
};

#endif // SSD1306Ascii_h
2 changes: 2 additions & 0 deletions config.example.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ The configuration file for DCC-EX Command Station
// 128x32 or 128x64 I2C SSD1306-based devices are supported.
// Use 132,64 for a SH1106-based I2C device with a 128x64 display.
// #define OLED_DRIVER 0x3c,128,32
// Uncomment the following line to flip the vertical orientation of the OLED display
// #define FLIP_OLED

// Define scroll mode as 0, 1 or 2
// * #define SCROLLMODE 0 is scroll continuous (fill screen if poss),
Expand Down
4 changes: 4 additions & 0 deletions myHal.cpp_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ void halSetup() {

//HALDisplay<OLED>::create(1, 0x3d, 128, 32);

// To invert the orientation of the OLED, add the Orientation::flipped parameter:

// HALDisplay<OLED>::create(1, 0x3d, 128, 32, Orientation::flipped);

// Create a 20x4 LCD display device as display number 2
// (line 0 is written by EX-RAIL 'SCREEN(2, 0, "text")').

Expand Down