🚸 Update Zonestar OLEDs to SPI (#27220)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
ellensp 2024-07-05 12:43:17 +12:00 committed by GitHub
parent 0103cffcd0
commit 1d1eb97567
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 456 additions and 166 deletions

View File

@ -654,11 +654,11 @@
#elif ENABLED(ZONESTAR_12864OLED)
#define IS_RRD_SC 1
#define U8GLIB_SH1106
#define U8GLIB_SH1106_SPI
#elif ENABLED(ZONESTAR_12864OLED_SSD1306)
#define IS_RRD_SC 1
#define IS_U8GLIB_SSD1306
#define U8GLIB_SSD1306_SPI
#elif ENABLED(RADDS_DISPLAY)
#define IS_ULTIPANEL 1
@ -716,7 +716,7 @@
#elif ENABLED(SAV_3DGLCD)
#ifdef U8GLIB_SSD1306
#if ENABLED(U8GLIB_SSD1306)
#define IS_U8GLIB_SSD1306 // Allow for U8GLIB_SSD1306 + SAV_3DGLCD
#endif
#define IS_NEWPANEL 1
@ -857,9 +857,12 @@
#define STD_ENCODER_STEPS_PER_MENU_ITEM 1
#endif
// 128x64 I2C OLED LCDs - SSD1306/SSD1309/SH1106
// 128x64 I2C OLED LCDs (SSD1306 / SSD1309 / SH1106)
// ...and 128x64 SPI OLED LCDs (SSD1306 / SH1106)
#if ANY(U8GLIB_SSD1306, U8GLIB_SSD1309, U8GLIB_SH1106)
#define HAS_U8GLIB_I2C_OLED 1
#endif
#if ANY(HAS_U8GLIB_I2C_OLED, U8GLIB_SSD1306_SPI, U8GLIB_SH1106_SPI)
#define HAS_WIRED_LCD 1
#define DOGLCD
#endif

View File

@ -154,9 +154,13 @@
#define FORCE_SOFT_SPI // SW-SPI
#if ENABLED(ALTERNATIVE_LCD)
#define U8G_CLASS U8GLIB_SH1306_128X64_2X // 4 stripes
#else
#if ENABLED(U8GLIB_SSD1306_SPI)
#define U8G_CLASS U8GLIB_SSD1306_128X64_SW_SPI_HAL
#else
#define U8G_CLASS U8GLIB_SH1306_128X64 // 8 stripes
#endif
#endif
#elif ANY(MKS_12864OLED, ZONESTAR_12864OLED)
@ -167,9 +171,13 @@
#define FORCE_SOFT_SPI // SW-SPI
#if ENABLED(ALTERNATIVE_LCD)
#define U8G_CLASS U8GLIB_SH1106_128X64_2X // 4 stripes
#else
#if ENABLED(U8GLIB_SH1106_SPI)
#define U8G_CLASS U8GLIB_SH1106_128X64_SW_SPI_HAL
#else
#define U8G_CLASS U8GLIB_SH1106_128X64 // 8 stripes
#endif
#endif
#elif ENABLED(U8GLIB_SH1106_EINSTART)

View File

@ -23,7 +23,7 @@
#include "../../../inc/MarlinConfig.h"
// use this file to create the public interface for device drivers that are NOT in the U8G library
// Use this file to create the public interface for device drivers that are NOT in the U8G library
extern u8g_dev_t u8g_dev_st7565_64128n_HAL_2x_sw_spi;
extern u8g_dev_t u8g_dev_st7565_64128n_HAL_2x_hw_spi;
@ -90,6 +90,30 @@ public:
void init(uint8_t options = U8G_I2C_OPT_NONE) { U8GLIB::init(&u8g_dev_ssd1306_128x64_2x_i2c_2_wire, options); }
};
#if ENABLED(U8GLIB_SH1106_SPI)
extern u8g_dev_t u8g_dev_sh1106_128x64_HAL_sw_spi;
class U8GLIB_SH1106_128X64_SW_SPI_HAL : public U8GLIB {
public:
U8GLIB_SH1106_128X64_SW_SPI_HAL() : U8GLIB() { }
U8GLIB_SH1106_128X64_SW_SPI_HAL(pin_t sck, pin_t mosi, pin_t cs, pin_t reset = U8G_PIN_NONE) {init(sck, mosi, cs, reset); }
void init(pin_t sck, pin_t mosi, pin_t cs, pin_t reset=U8G_PIN_NONE) {
U8GLIB::init(&u8g_dev_sh1106_128x64_HAL_sw_spi, (uint8_t)sck, (uint8_t)mosi, (uint8_t)cs, U8G_PIN_NONE, (uint8_t)reset);
}
};
#endif
#if ENABLED(U8GLIB_SSD1306_SPI)
extern u8g_dev_t u8g_dev_ssd1306_128x64_HAL_sw_spi;
class U8GLIB_SSD1306_128X64_SW_SPI_HAL : public U8GLIB {
public:
U8GLIB_SSD1306_128X64_SW_SPI_HAL() : U8GLIB() { }
U8GLIB_SSD1306_128X64_SW_SPI_HAL(pin_t sck, pin_t mosi, pin_t cs, pin_t reset = U8G_PIN_NONE) {init(sck, mosi, cs, reset); }
void init(pin_t sck, pin_t mosi, pin_t cs, pin_t reset=U8G_PIN_NONE) {
U8GLIB::init(&u8g_dev_ssd1306_128x64_HAL_sw_spi, (uint8_t)sck, (uint8_t)mosi, (uint8_t)cs, U8G_PIN_NONE, (uint8_t)reset);
}
};
#endif
//
// Very basic support for 320x240 TFT screen
// Tested on MKS Robin TFT_V2.0 with ST7789V controller

View File

@ -77,17 +77,11 @@
uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq);
// The sh1106 is compatible to the ssd1306, but is 132x64. 128x64 display area is centered within
// the 132x64.
static const uint8_t u8g_dev_sh1106_128x64_data_start_2_wire[] PROGMEM = {
0x010, // set upper 4 bit of the col adr to 0
0x002, // set lower 4 bit of the col adr to 2 (centered display with ssd1306)
U8G_ESC_END // end of sequence
};
// SH1106 (132x64) is compatible with SSD1306 (128x64) by adding a small margin to the larger display
#define SH1106_PAGE_ADR(N) (0x20), (N)
#define SH1106_COLUMN_RANGE(N) (0x21), (((N) >> 8) & 0xFF), ((N) & 0xFF)
#define SH1106_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF)
#define SH1106_COLUMN_RANGE(N,O) (0x21), (N), (O)
#define SH1106_PAGE_RANGE(N,O) (0x22), (N), (O)
#define SH1106_SCROLL(N) ((N) ? 0x2F : 0x2E)
#define SH1106_START_LINE(N) (0x40 | (N))
@ -106,6 +100,11 @@ static const uint8_t u8g_dev_sh1106_128x64_data_start_2_wire[] PROGMEM = {
#define SH1106_VCOM_DESEL(N) (0xDB), (N)
#define SH1106_NOOP() (0xE3)
static const uint8_t u8g_dev_sh1106_128x64_data_start_2_wire[] PROGMEM = {
SH1106_COL_ADR(2), // Column 2 to center 128 pixels in 132 pixels
U8G_ESC_END // End of sequence
};
static const uint8_t u8g_dev_sh1106_128x64_init_seq_2_wire[] PROGMEM = {
U8G_ESC_ADR(0), // Initiate command mode
SH1106_ON(0), // Display off, sleep mode
@ -113,19 +112,19 @@ static const uint8_t u8g_dev_sh1106_128x64_init_seq_2_wire[] PROGMEM = {
SH1106_DISP_OFFS(0), // Display offset
SH1106_START_LINE(0), // Start line
SH1106_ADC_REVERSE(1), // Segment remap A0/A1
SH1106_OUT_MODE(1), // C0: scan dir normal, C8: reverse
SH1106_COM_CONFIG(1), // Com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SH1106_CONTRAST(0xCF), // [2] set contrast control
SH1106_PAGE_ADR(0x02), // 2012-05-27: page addressing mode
SH1106_COLUMN_RANGE(0x281), // Set column range from 0 through 131
SH1106_PAGE_RANGE(0, 7), // Set page range from 0 through 7
SH1106_CHARGE_PER(0x1, 0xF), // [2] pre-charge period 0x22/F1
SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse
SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SH1106_CONTRAST(0xCF), // Set contrast control
SH1106_PAGE_ADR(0x02), // page addressing mode
SH1106_COLUMN_RANGE(2, 129), // Set column range 2 .. 129
SH1106_PAGE_RANGE(0, 7), // Set page range 0 .. 7
SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period
SH1106_VCOM_DESEL(0x40), // Vcomh deselect level
SH1106_ALL_PIX(0), // Output ram to display
SH1106_ALL_PIX(0), // Output RAM to display
SH1106_INVERTED(0), // Normal display mode
SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8)
SH1106_CHARGE_PUMP(1), // [2] charge pump setting (P62): 0x14 enable, 0x10 disable
SH1106_SCROLL(0), // 2012-05-27: Deactivate scroll
SH1106_CHARGE_PUMP(1), // Charge pump setting
SH1106_SCROLL(0), // Deactivate scroll
SH1106_ON(1), // Display on
U8G_ESC_END // End of sequence
};
@ -136,28 +135,24 @@ uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t m
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_init_seq_2_wire);
break;
case U8G_DEV_MSG_STOP:
break;
case U8G_DEV_MSG_STOP: break;
case U8G_DEV_MSG_PAGE_NEXT: {
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
u8g_SetAddress(u8g, dev, 0); // instruction mode
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire);
u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2)); // select current page
u8g_SetAddress(u8g, dev, 1); // data mode
u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2)); // Select current page
u8g_SetAddress(u8g, dev, 1); // Data mode
u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf);
u8g_SetChipSelect(u8g, dev, 0);
u8g_SetAddress(u8g, dev, 0); // instruction mode
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire);
u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2+1)); // select current page
u8g_SetAddress(u8g, dev, 1); // data mode
u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2+1)); // Select current page
u8g_SetAddress(u8g, dev, 1); // Data mode
u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width);
u8g_SetChipSelect(u8g, dev, 0);
}
break;
case U8G_DEV_MSG_SLEEP_ON:
return 1;
case U8G_DEV_MSG_SLEEP_OFF:
return 1;
} break;
case U8G_DEV_MSG_SLEEP_ON: return 1;
case U8G_DEV_MSG_SLEEP_OFF: return 1;
}
return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg);
}
@ -169,33 +164,32 @@ u8g_dev_t u8g_dev_sh1106_128x64_2x_i2c_2_wire = { u8g_dev_sh1106_128x64_2x_2_wir
/////////////////////////////////////////////////////////////////////////////////////////////
static const uint8_t u8g_dev_ssd1306_128x64_data_start_2_wire[] PROGMEM = {
0x010, // set upper 4 bit of the col adr to 0
0x000, // set lower 4 bit of the col adr to 0
U8G_ESC_END // end of sequence
SH1106_COL_ADR(0), // Column 0
U8G_ESC_END // End of sequence
};
static const uint8_t u8g_dev_ssd1306_128x64_init_seq_2_wire[] PROGMEM = {
U8G_ESC_ADR(0), // initiate command mode
0x0AE, // display off, sleep mode
0x0A8, 0x03F, // mux ratio
0x0D3, 0x00, // display offset
0x040, // start line
0x0A1, // segment remap a0/a1
0x0C8, // c0: scan dir normal, c8: reverse
0x0DA, 0x012, // com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
0x081, 0x0CF, // [2] set contrast control
0x020, 0x002, // 2012-05-27: page addressing mode
0x21, 0, 0x7F, // set column range from 0 through 127
0x22, 0, 7, // set page range from 0 through 7
0x0D9, 0x0F1, // [2] pre-charge period 0x022/f1
0x0DB, 0x040, // vcomh deselect level
0x0A4, // output ram to display
0x0A6, // none inverted normal display mode
0x0D5, 0x080, // clock divide ratio (0x00=1) and oscillator frequency (0x8)
0x08D, 0x014, // [2] charge pump setting (p62): 0x014 enable, 0x010 disable
0x02E, // 2012-05-27: Deactivate scroll
0x0AF, // display on
U8G_ESC_END // end of sequence
U8G_ESC_CS(0), // Disable chip
SH1106_ON(0), // Display off, sleep mode
SH1106_MUX_RATIO(0x3F), // Mux ratio
SH1106_DISP_OFFS(0), // Display offset
SH1106_START_LINE(0), // Start line
SH1106_ADC_REVERSE(1), // Segment remap A0/A1
SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse
SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SH1106_CONTRAST(0xCF), // Set contrast control
SH1106_PAGE_ADR(0x02), // page addressing mode
SH1106_COLUMN_RANGE(0, 127), // Set column range 0 .. 127
SH1106_PAGE_RANGE(0, 7), // Set page range from 0 .. 7
SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period
SH1106_VCOM_DESEL(0x40), // Vcomh deselect level
SH1106_ALL_PIX(0), // Send RAM to display
SH1106_INVERTED(0), // Normal display mode
SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8)
SH1106_CHARGE_PUMP(1), // Charge pump setting
SH1106_SCROLL(0), // Deactivate scroll
SH1106_ON(1), // Display on
U8G_ESC_END // End of sequence
};
uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
@ -204,28 +198,24 @@ uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_init_seq_2_wire);
break;
case U8G_DEV_MSG_STOP:
break;
case U8G_DEV_MSG_STOP: break;
case U8G_DEV_MSG_PAGE_NEXT: {
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
u8g_SetAddress(u8g, dev, 0); // instruction mode
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire);
u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2)); // select current page
u8g_SetAddress(u8g, dev, 1); // data mode
u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2)); // Select current page
u8g_SetAddress(u8g, dev, 1); // Data mode
u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf);
u8g_SetChipSelect(u8g, dev, 0);
u8g_SetAddress(u8g, dev, 0); // instruction mode
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire);
u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2+1)); // select current page
u8g_SetAddress(u8g, dev, 1); // data mode
u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2+1)); // Select current page
u8g_SetAddress(u8g, dev, 1); // Data mode
u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width);
u8g_SetChipSelect(u8g, dev, 0);
}
break;
case U8G_DEV_MSG_SLEEP_ON:
return 1;
case U8G_DEV_MSG_SLEEP_OFF:
return 1;
} break;
case U8G_DEV_MSG_SLEEP_ON: return 1;
case U8G_DEV_MSG_SLEEP_OFF: return 1;
}
return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg);
}
@ -236,10 +226,10 @@ u8g_dev_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire = { u8g_dev_ssd1306_128x64_2x_2_w
/////////////////////////////////////////////////////////////////////////////////////////////
// This routine adds the instruction byte in between the command bytes. This makes the init
// sequences a lot easier to read.
// This routine adds the instruction byte in between the command bytes.
// This makes the init sequences a lot easier to read.
#define I2C_CMD_MODE 0x080
#define I2C_CMD_MODE 0x80
uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq) {
uint8_t is_escape = 0;
@ -247,10 +237,8 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s
uint8_t value = u8g_pgm_read(esc_seq);
if (is_escape == 0) {
if (value != 255) {
if (u8g_WriteByte(u8g, dev, value) == 0 )
return 0;
if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0 )
return 0;
if (u8g_WriteByte(u8g, dev, value) == 0) return 0;
if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0) return 0;
}
else {
is_escape = 1;
@ -258,16 +246,14 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s
}
else {
if (value == 255) {
if (u8g_WriteByte(u8g, dev, value) == 0 )
return 0;
if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0 )
return 0;
if (u8g_WriteByte(u8g, dev, value) == 0) return 0;
if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0) return 0;
}
else if (value == 254) {
break;
}
else if (value >= 0x0F0) {
/* not yet used, do nothing */
else if (value >= 0xF0) {
// not yet used, do nothing
}
else if (value >= 0xE0 ) {
u8g_SetAddress(u8g, dev, value & 0x0F);
@ -279,13 +265,14 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s
u8g_SetResetLow(u8g, dev);
value &= 0x0F;
value <<= 4;
value+=2;
value += 2;
u8g_Delay(value);
u8g_SetResetHigh(u8g, dev);
u8g_Delay(value);
}
else if (value >= 0xBE) { /* not yet implemented */
/* u8g_SetVCC(u8g, dev, value & 0x01); */
else if (value >= 0xBE) {
// not yet implemented
//u8g_SetVCC(u8g, dev, value & 0x01);
}
else if (value <= 127) {
u8g_Delay(value);

View File

@ -0,0 +1,246 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_dev_ssd1306_128x64.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2015, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "../../../inc/MarlinConfig.h"
#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) && ANY(U8GLIB_SH1106_SPI, U8GLIB_SSD1306_SPI)
#include "HAL_LCD_com_defines.h"
#define WIDTH 128
#define HEIGHT 64
#define PAGE_HEIGHT 8
#define SH1106_PAGE_ADR(N) (0x20), (N)
#define SH1106_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF)
#define SH1106_COLUMN_RANGE(N,O) (0x21), (N), (O)
#define SH1106_PAGE_RANGE(N,O) (0x22), (N), (O)
#define SH1106_SCROLL(N) ((N) ? 0x2F : 0x2E)
#define SH1106_START_LINE(N) (0x40 | (N))
#define SH1106_CONTRAST(N) (0x81), (N)
#define SH1106_CHARGE_PUMP(N) (0x8D), ((N) ? 0x14 : 0x10)
#define SH1106_ADC_REVERSE(N) ((N) ? 0xA1 : 0xA0)
#define SH1106_ALL_PIX(N) ((N) ? 0xA5 : 0xA4)
#define SH1106_INVERTED(N) ((N) ? 0xA7 : 0xA6)
#define SH1106_MUX_RATIO(N) (0xA8), (N)
#define SH1106_ON(N) ((N) ? 0xAF : 0xAE)
#define SH1106_OUT_MODE(N) ((N) ? 0xC8 : 0xC0)
#define SH1106_DISP_OFFS(N) (0xD3), (N)
#define SH1106_OSC_FREQ(R,F) (0xD5), ((F) << 4 | (R))
#define SH1106_CHARGE_PER(P,D) (0xD9), ((D) << 4 | (P))
#define SH1106_COM_CONFIG(N) (0xDA), ((N) ? 0x12 : 0x02)
#define SH1106_VCOM_DESEL(N) (0xDB), (N)
#define SH1106_NOOP() (0xE3)
static const uint8_t u8g_dev_ssd13xx_HAL_sleep_on[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
SH1106_ON(0) // Display off
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
};
static const uint8_t u8g_dev_ssd13xx_HAL_sleep_off[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
SH1106_ON(1), // Display on
U8G_ESC_DLY(50), // Delay 50 ms
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
};
#if ENABLED(U8GLIB_SH1106_SPI)
// Init sequence Adafruit 128x64 OLED (NOT TESTED). Like Adafruit3, but with page addressing mode.
static const uint8_t u8g_dev_sh1106_128x64_HAL_init_seq[] PROGMEM = {
U8G_ESC_CS(0), // Disable chip
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_RST(1), // Do reset low pulse with (1*16)+2 milliseconds
U8G_ESC_CS(1), // Enable chip
SH1106_ON(0), // Display off, sleep mode
SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8)
SH1106_MUX_RATIO(0x3F), // Mux ratio
SH1106_DISP_OFFS(0), // Display offset
SH1106_START_LINE(0), // Start line
SH1106_CHARGE_PUMP(1), // Charge pump setting
SH1106_PAGE_ADR(0x02), // page addressing mode
SH1106_ADC_REVERSE(1), // Segment remap A0/A1
SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse
SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SH1106_CONTRAST(0x80), // Set contrast control
SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period
SH1106_VCOM_DESEL(0x40), // Vcomh deselect level
SH1106_SCROLL(0), // Deactivate scroll
SH1106_ALL_PIX(0), // Output RAM to display
SH1106_INVERTED(0), // Normal display mode
SH1106_ON(1), // Display on
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
};
// SH1106 (132x64) is compatible with SSD1306 (128x64) by adding a small margin to the larger display
static const uint8_t u8g_dev_sh1106_128x64_HAL_data_start[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
SH1106_COL_ADR(2), // Column 2 to center 128 pixels in 132 pixels
U8G_ESC_END // End of sequence
};
uint8_t u8g_dev_sh1106_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
switch(msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
u8g_WriteEscSeqP(u8g, dev, u8g_dev_sh1106_128x64_HAL_init_seq);
break;
case U8G_DEV_MSG_STOP:
break;
case U8G_DEV_MSG_PAGE_NEXT: {
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
u8g_WriteEscSeqP(u8g, dev, u8g_dev_sh1106_128x64_HAL_data_start);
u8g_WriteByte(u8g, dev, 0x0B0 | pb->p.page); // Select current page (SSD1306)
u8g_SetAddress(u8g, dev, 1); // Data mode
if (u8g_pb_WriteBuffer(pb, u8g, dev) == 0) return 0;
u8g_SetChipSelect(u8g, dev, 0);
} break;
case U8G_DEV_MSG_SLEEP_ON:
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd13xx_HAL_sleep_on);
return 1;
case U8G_DEV_MSG_SLEEP_OFF:
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd13xx_HAL_sleep_off);
return 1;
case U8G_DEV_MSG_CONTRAST:
u8g_SetChipSelect(u8g, dev, 1);
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteByte(u8g, dev, 0x81);
u8g_WriteByte(u8g, dev, *(uint8_t *) arg);
u8g_SetChipSelect(u8g, dev, 0);
return 1;
}
return u8g_dev_pb8v1_base_fn(u8g, dev, msg, arg);
}
U8G_PB_DEV(u8g_dev_sh1106_128x64_HAL_sw_spi, WIDTH, HEIGHT, PAGE_HEIGHT, u8g_dev_sh1106_128x64_HAL_fn, U8G_COM_HAL_SW_SPI_FN);
#elif ENABLED(U8GLIB_SSD1306_SPI)
static const uint8_t u8g_dev_ssd1306_128x64_HAL_init_seq[] PROGMEM = {
U8G_ESC_CS(0), // Disable chip
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_RST(1), // Do reset low pulse with (1*16)+2 milliseconds
U8G_ESC_CS(1), // Enable chip
SH1106_ON(0), // Display off, sleep mode
SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8)
SH1106_MUX_RATIO(0x3F), // Mux ratio
SH1106_DISP_OFFS(0), // Display offset
SH1106_START_LINE(0), // Start line
SH1106_CHARGE_PUMP(1), // Charge pump setting
SH1106_PAGE_ADR(0x02), // page addressing mode
SH1106_ADC_REVERSE(1), // Segment remap A0/A1
SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse
SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SH1106_CONTRAST(0x80), // Set contrast control
SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period
SH1106_VCOM_DESEL(0x40), // Vcomh deselect level
SH1106_SCROLL(0), // Deactivate scroll
SH1106_ALL_PIX(0), // Output RAM to display
SH1106_INVERTED(0), // Normal display mode
SH1106_ON(1), // Display on
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
};
static const uint8_t u8g_dev_ssd1306_128x64_HAL_data_start[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
SH1106_COL_ADR(0), // Column 0
U8G_ESC_END // End of sequence
};
uint8_t u8g_dev_ssd1306_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
switch(msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd1306_128x64_HAL_init_seq);
break;
case U8G_DEV_MSG_STOP: break;
case U8G_DEV_MSG_PAGE_NEXT: {
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd1306_128x64_HAL_data_start);
u8g_WriteByte(u8g, dev, 0x0b0 | pb->p.page); // Select current page (SSD1306)
u8g_SetAddress(u8g, dev, 1); // Data mode
if (u8g_pb_WriteBuffer(pb, u8g, dev) == 0) return 0;
u8g_SetChipSelect(u8g, dev, 0);
} break;
case U8G_DEV_MSG_SLEEP_ON:
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd13xx_HAL_sleep_on);
return 1;
case U8G_DEV_MSG_SLEEP_OFF:
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd13xx_HAL_sleep_off);
return 1;
case U8G_DEV_MSG_CONTRAST:
u8g_SetChipSelect(u8g, dev, 1);
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteByte(u8g, dev, 0x81);
u8g_WriteByte(u8g, dev, *(uint8_t *) arg);
u8g_SetChipSelect(u8g, dev, 0);
return 1;
}
return u8g_dev_pb8v1_base_fn(u8g, dev, msg, arg);
}
U8G_PB_DEV(u8g_dev_ssd1306_128x64_HAL_sw_spi, WIDTH, HEIGHT, PAGE_HEIGHT, u8g_dev_ssd1306_128x64_HAL_fn, U8G_COM_HAL_SW_SPI_FN);
#endif // U8GLIB_SSD1306_SPI
#endif // HAS_MARLINUI_U8GLIB

View File

@ -31,6 +31,28 @@
#define HEIGHT 64
#define PAGE_HEIGHT 8
#define SSD1309_PAGE_ADR(N) (0x20), (N)
#define SSD1309_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF)
#define SSD1309_COLUMN_RANGE(N,O) (0x21), (N), (O)
#define SSD1309_PAGE_RANGE(N,O) (0x22), (N), (O)
#define SSD1309_SCROLL(N) ((N) ? 0x2F : 0x2E)
#define SSD1309_START_LINE(N) (0x40 | (N))
#define SSD1309_CONTRAST(N) (0x81), (N)
#define SSD1309_CHARGE_PUMP(N) (0x8D), ((N) ? 0x14 : 0x10)
#define SSD1309_ADC_REVERSE(N) ((N) ? 0xA1 : 0xA0)
#define SSD1309_ALL_PIX(N) ((N) ? 0xA5 : 0xA4)
#define SSD1309_INVERTED(N) ((N) ? 0xA7 : 0xA6)
#define SSD1309_MUX_RATIO(N) (0xA8), (N)
#define SSD1309_ON(N) ((N) ? 0xAF : 0xAE)
#define SSD1309_OUT_MODE(N) ((N) ? 0xC8 : 0xC0)
#define SSD1309_DISP_OFFS(N) (0xD3), (N)
#define SSD1309_OSC_FREQ(R,F) (0xD5), ((F) << 4 | (R))
#define SSD1309_CHARGE_PER(P,D) (0xD9), ((D) << 4 | (P))
#define SSD1309_COM_CONFIG(N) (0xDA), ((N) ? 0x12 : 0x02)
#define SSD1309_VCOM_DESEL(N) (0xDB), (N)
#define SSD1309_NOOP() (0xE3)
#define SSD1309_COMMAND_LOCK(N) (0xFD), ((N) ? 0x16 : 0x12)
// SSD1309 init sequence
static const uint8_t u8g_dev_ssd1309_128x64_init_seq[] PROGMEM = {
U8G_ESC_CS(0), // Disable chip
@ -38,23 +60,24 @@ static const uint8_t u8g_dev_ssd1309_128x64_init_seq[] PROGMEM = {
U8G_ESC_RST(1), // Do reset low pulse with (1*16)+2 milliseconds
U8G_ESC_CS(1), // Enable chip
0xFD,0x12, // Command Lock
0xAE, // Set Display Off
0xD5,0xA0, // Set Display Clock Divide Ratio/Oscillator Frequency
0xA8,0x3F, // Set Multiplex Ratio
0x3D,0x00, // Set Display Offset
0x40, // Set Display Start Line
0xA1, // Set Segment Re-Map
0xC8, // Set COM Output Scan Direction
0xDA,0x12, // Set COM Pins Hardware Configuration
0x81,0xDF, // Set Current Control
0xD9,0x82, // Set Pre-Charge Period
0xDB,0x34, // Set VCOMH Deselect Level
0xA4, // Set Entire Display On/Off
0xA6, // Set Normal/Inverse Display
U8G_ESC_VCC(1), // Power up VCC & Stabilized
SSD1309_COMMAND_LOCK(0), // Unlock OLED driver IC MCU command interface
SSD1309_ON(0),
SSD1309_OSC_FREQ(0, 10), // Clock divide ratio (0:1) and oscillator frequency (8)
SSD1309_MUX_RATIO(0x3F), // Mux ratio
SSD1309_DISP_OFFS(0), // Display offset
SSD1309_START_LINE(0), // Start line
SSD1309_ADC_REVERSE(1), // Segment remap A0/A1
SSD1309_OUT_MODE(1), // 0: scan dir normal, 1: reverse
SSD1309_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
SSD1309_CONTRAST(0xDF), // Set contrast control
SSD1309_CHARGE_PER(0x2, 0x8), // Pre-charge period
SSD1309_VCOM_DESEL(0x34), // Vcomh deselect level
SSD1309_ALL_PIX(0), // Output RAM to display
SSD1309_INVERTED(0), // Normal display mode
U8G_ESC_VCC(1), // Power up VCC & stabilize
U8G_ESC_DLY(50),
0xAF, // Set Display On
SSD1309_ON(1), // Display on
U8G_ESC_DLY(50),
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
@ -66,15 +89,14 @@ static const uint8_t u8g_dev_ssd1309_128x64_init_seq[] PROGMEM = {
static const uint8_t u8g_dev_ssd1309_128x64_data_start[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
0x010, // Set upper 4 bit of the col adr to 0
0x000, // Set lower 4 bit of the col adr to 4
SSD1309_COL_ADR(0), // Column 0
U8G_ESC_END // End of sequence
};
static const uint8_t u8g_dev_ssd13xx_sleep_on[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
0x0AE, // Display off
SSD1309_ON(0), // Display off
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
};
@ -82,7 +104,7 @@ static const uint8_t u8g_dev_ssd13xx_sleep_on[] PROGMEM = {
static const uint8_t u8g_dev_ssd13xx_sleep_off[] PROGMEM = {
U8G_ESC_ADR(0), // Instruction mode
U8G_ESC_CS(1), // Enable chip
0x0AF, // Display on
SSD1309_ON(1), // Display on
U8G_ESC_DLY(50), // Delay 50 ms
U8G_ESC_CS(0), // Disable chip
U8G_ESC_END // End of sequence
@ -99,7 +121,7 @@ uint8_t u8g_dev_ssd1309_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void
case U8G_DEV_MSG_PAGE_NEXT: {
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd1309_128x64_data_start);
u8g_WriteByte(u8g, dev, 0x0B0 | pb->p.page); // Select current page (SSD1306)
u8g_WriteByte(u8g, dev, 0xB0 | pb->p.page); // Select current page (SSD1306)
u8g_SetAddress(u8g, dev, 1); // Data mode
if (u8g_pb_WriteBuffer(pb, u8g, dev) == 0) return 0;
u8g_SetChipSelect(u8g, dev, 0);
@ -108,8 +130,8 @@ uint8_t u8g_dev_ssd1309_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void
case U8G_DEV_MSG_CONTRAST:
u8g_SetChipSelect(u8g, dev, 1);
u8g_SetAddress(u8g, dev, 0); // Instruction mode
u8g_WriteByte(u8g, dev, 0x081);
u8g_WriteByte(u8g, dev, (*(uint8_t *)arg) ); // 11 Jul 2015: fixed contrast calculation
u8g_WriteByte(u8g, dev, 0x81);
u8g_WriteByte(u8g, dev, (*(uint8_t *)arg));
u8g_SetChipSelect(u8g, dev, 0);
return 1;
case U8G_DEV_MSG_SLEEP_ON:

View File

@ -130,7 +130,7 @@ static const uint8_t u8g_dev_uc1701_mini12864_HAL_data_start[] PROGMEM = {
UC1701_V5_RATIO(3), // set V0 voltage resistor ratio to large
UC1701_INDICATOR(0), // indicator disable
UC1701_ON(1), // display on
UC1701_COLUMN_HI(0), // set upper 4 bit of the col adr to 0
UC1701_COLUMN_HI(0), // set upper 4 bits of the col adr to 0
U8G_ESC_END, // end of sequence
U8G_ESC_DLY(5) // delay 5 ms
#else