Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32 I2C two wire LCD - bug fix and soft I2C driver implementation #26433

Open
wants to merge 36 commits into
base: bugfix-2.1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
637983d
F103 testing
Bob-the-Kuhn Nov 15, 2023
14e57de
Update u8g_com_stm32duino_ssd_i2c.cpp
Bob-the-Kuhn Nov 16, 2023
e581b2b
Added protection to keep from un-necessarily compiling u8g_dev_ssd130…
Bob-the-Kuhn Nov 17, 2023
e7f6fdc
misc. cleanup
thinkyhead Nov 25, 2023
2c3f6cd
run time selection of soft vs. hard I2C drivers
Bob-the-Kuhn Dec 6, 2023
69da85b
KLEM test error fix - use current macro
Bob-the-Kuhn Dec 6, 2023
218ffa0
fix typo in marlinui_DOGM.h
Bob-the-Kuhn Dec 7, 2023
e1b9a4d
adjust
thinkyhead Dec 9, 2023
3705f77
clean up
thinkyhead Dec 9, 2023
fc98192
single SlowSoftWire
thinkyhead Dec 9, 2023
607d837
followup
thinkyhead Dec 9, 2023
892c347
apply standard
thinkyhead Dec 9, 2023
1f2148e
Allow compile-time optimization
thinkyhead Dec 9, 2023
690fc49
ws
thinkyhead Dec 9, 2023
3a5d488
filter soft i2c libraries
thinkyhead Dec 11, 2023
fdd617a
use proper flag, tweak test
thinkyhead Dec 11, 2023
ad8b91a
conditional
thinkyhead Dec 11, 2023
fad7d7d
remove LCDSCREEN_NAME
thinkyhead Dec 11, 2023
4af6a75
move conditionals, add test
thinkyhead Dec 11, 2023
87a8f14
split up and filter
thinkyhead Dec 12, 2023
d410e6e
fix a warn
thinkyhead Dec 12, 2023
7c34822
headers
thinkyhead Dec 12, 2023
e8189c0
fix flags
thinkyhead Dec 12, 2023
5119dd3
more flags
thinkyhead Dec 12, 2023
2a05fc0
need u8g
thinkyhead Dec 12, 2023
bf79fb9
move extern
thinkyhead Dec 12, 2023
64f6836
get pin_t
thinkyhead Dec 12, 2023
0479483
encoder tweak
thinkyhead Dec 12, 2023
43c0ad2
retry later
thinkyhead Dec 13, 2023
3cbaa5a
Merge branch 'bugfix-2.1.x' into pr/26433
thinkyhead Dec 27, 2023
3d34cc8
merge followup
thinkyhead Dec 27, 2023
da724c1
shared commands
thinkyhead Dec 27, 2023
addf2ad
fix u8g init typo
thinkyhead Jan 4, 2024
7772c7d
Merge branch 'bugfix-2.1.x' into pr/26433
thinkyhead Jan 4, 2024
792edeb
comma
thinkyhead Jan 4, 2024
4b07a32
Merge branch 'bugfix-2.1.x' into pr/26433
thinkyhead Jan 26, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@

#if defined(ARDUINO) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAM)

#include "../../inc/MarlinConfigPre.h"
#include "../../../inc/MarlinConfigPre.h"

#if HAS_MARLINUI_U8GLIB

#include "../shared/Marduino.h"
#include "../shared/Delay.h"
#include "../../shared/Marduino.h"
#include "../../shared/Delay.h"

#include <U8glib-HAL.h>

Expand Down
2 changes: 2 additions & 0 deletions Marlin/src/HAL/STM32/u8g/LCD_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

uint8_t u8g_com_std_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL
uint8_t u8g_com_stm32duino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL
uint8_t u8g_com_stm32duino_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#define U8G_COM_HAL_SW_SPI_FN u8g_com_std_sw_spi_fn
#define U8G_COM_HAL_HW_SPI_FN u8g_com_stm32duino_hw_spi_fn
#define U8G_COM_SSD_I2C_HAL u8g_com_stm32duino_ssd_i2c_fn
194 changes: 194 additions & 0 deletions Marlin/src/HAL/STM32/u8g/u8g_com_stm32duino_ssd_i2c.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 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/>.
*
*/

/**
* 2-Wire I2C COM Driver
*
* Handles both Hardware and Software I2C so any pins can be used as SDA and SLC.
* Wire library is used for Hardware I2C.
* SlowSoftWire is used for Software I2C.
*
* Wire / SoftWire library selection can be done automatically at runtime.
*
* SDA and SLC pins must be named DOGLCD_SDA_PIN, DOGLCD_SCL_PIN to distinguish
* from other I2C devices (e.g., EEPROM) that use I2C_SDA_PIN, I2C_SLC_PIN.
*/
#ifdef ARDUINO_ARCH_STM32

#include "../../../inc/MarlinConfig.h"

#if HAS_U8GLIB_I2C_OLED

#include <U8glib-HAL.h>

#if ENABLED(U8G_USES_HW_I2C)
#include <Wire.h>
#ifndef MASTER_ADDRESS
#define MASTER_ADDRESS 0x01
#endif
#endif

#if ENABLED(U8G_USES_SW_I2C)
#include <SlowSoftI2CMaster.h>
#include <SlowSoftWire.h>
#endif

/**
* BUFFER_LENGTH is defined in libraries\Wire\utility\WireBase.h
* Default value is 32
* Increase this value to 144 to send U8G_COM_MSG_WRITE_SEQ in single block
*/
#ifndef BUFFER_LENGTH
#define BUFFER_LENGTH 32
#endif
#if BUFFER_LENGTH > 144
#error "BUFFER_LENGTH should not be greater than 144."
#endif
#define I2C_MAX_LENGTH (BUFFER_LENGTH - 1)

uint8_t u8g_com_stm32duino_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
// Hardware I2C flag
#ifdef COMPILE_TIME_I2C_IS_HARDWARE
constexpr bool isHardI2C = ENABLED(COMPILE_TIME_I2C_IS_HARDWARE);
#else
static bool isHardI2C = false;
static bool i2c_initialized = false; // Flag to only run init/linking code once
if (!i2c_initialized) { // Init runtime linkages
i2c_initialized = true; // Only do this once
I2C_TypeDef *i2cInstance1 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SDA_PIN), PinMap_I2C_SDA);
I2C_TypeDef *i2cInstance2 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SCL_PIN), PinMap_I2C_SCL);
isHardI2C = (i2cInstance1 && (i2cInstance1 == i2cInstance2)); // Found hardware I2C controller
}
#endif

static uint8_t msgInitCount = 0; // Ignore all messages until 2nd U8G_COM_MSG_INIT
if (msgInitCount) {
if (msg == U8G_COM_MSG_INIT) msgInitCount--;
if (msgInitCount) return -1;
}

static uint8_t control;
if (isHardI2C) { // Found hardware I2C controller
#if ENABLED(U8G_USES_HW_I2C)
static TwoWire wire2; // A TwoWire object for use below
switch (msg) {
case U8G_COM_MSG_INIT:
wire2.setClock(400000);
wire2.setSCL(DOGLCD_SCL_PIN);
wire2.setSDA(DOGLCD_SDA_PIN);
wire2.begin(MASTER_ADDRESS, 0); // Start as master
break;

case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1)
control = arg_val ? 0x40 : 0x00;
break;

case U8G_COM_MSG_WRITE_BYTE:
wire2.beginTransmission(0x3C);
wire2.write(control);
wire2.write(arg_val);
wire2.endTransmission();
break;

case U8G_COM_MSG_WRITE_SEQ: {
uint8_t* dataptr = (uint8_t*)arg_ptr;
#ifdef I2C_MAX_LENGTH
while (arg_val > 0) {
wire2.beginTransmission(0x3C);
wire2.write(control);
if (arg_val <= I2C_MAX_LENGTH) {
wire2.write(dataptr, arg_val);
arg_val = 0;
}
else {
wire2.write(dataptr, I2C_MAX_LENGTH);
arg_val -= I2C_MAX_LENGTH;
dataptr += I2C_MAX_LENGTH;
}
wire2.endTransmission();
}
#else
wire2.beginTransmission(0x3C);
wire2.write(control);
wire2.write(dataptr, arg_val);
wire2.endTransmission();
#endif // I2C_MAX_LENGTH
break;
}
}
#endif
}
else { // Software I2C
#if ENABLED(U8G_USES_SW_I2C)
static SlowSoftWire sWire = SlowSoftWire(DOGLCD_SDA_PIN, DOGLCD_SCL_PIN);

switch (msg) {
case U8G_COM_MSG_INIT:
sWire.setClock(400000);
sWire.begin(); // Start as master
break;

case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1)
control = arg_val ? 0x40 : 0x00;
break;

case U8G_COM_MSG_WRITE_BYTE:
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
sWire.write((uint8_t)arg_val);
sWire.endTransmission();
break;

case U8G_COM_MSG_WRITE_SEQ: {
uint8_t* dataptr = (uint8_t*)arg_ptr;
#ifdef I2C_MAX_LENGTH
while (arg_val > 0) {
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
if (arg_val <= I2C_MAX_LENGTH) {
sWire.write((const uint8_t *)dataptr, (size_t)arg_val);
arg_val = 0;
}
else {
sWire.write((const uint8_t *)dataptr, I2C_MAX_LENGTH);
arg_val -= I2C_MAX_LENGTH;
dataptr += I2C_MAX_LENGTH;
}
sWire.endTransmission();
}
#else
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
sWire.write((const uint8_t *)dataptr, (size_t)arg_val);
sWire.endTransmission();
#endif // I2C_MAX_LENGTH
break;
}
}
#endif
}

return 1;
}

#endif // HAS_U8GLIB_I2C_OLED
#endif // ARDUINO_ARCH_STM32
20 changes: 18 additions & 2 deletions Marlin/src/inc/Conditionals_LCD.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@
#define DOGLCD
#define IS_U8GLIB_ST7920 1
#define IS_ULTIPANEL 1
#define ENCODER_PULSES_PER_STEP 2
#define STD_ENCODER_PULSES_PER_STEP 2

#elif ENABLED(MKS_12864OLED)

Expand Down Expand Up @@ -831,6 +831,7 @@
#endif
#endif

// U8GLIB_SSD1306 may be set alone or for other displays that need it
#if ENABLED(IS_U8GLIB_SSD1306)
#define U8GLIB_SSD1306
#endif
Expand All @@ -854,10 +855,25 @@
#endif

// 128x64 I2C OLED LCDs - SSD1306/SSD1309/SH1106
#if ANY(U8GLIB_SSD1306, U8GLIB_SSD1309, U8GLIB_SH1106)
#if ANY(U8GLIB_SH1106, U8GLIB_SSD1306, U8GLIB_SSD1309)
#define HAS_U8GLIB_I2C_OLED 1
#define HAS_WIRED_LCD 1
#define DOGLCD

// Define this to reduce build size and optimize performance
//#define COMPILE_TIME_I2C_IS_HARDWARE true // true: Hardware false: Software undefined: Solve at runtime

#ifdef COMPILE_TIME_I2C_IS_HARDWARE
#if COMPILE_TIME_I2C_IS_HARDWARE
#define U8G_USES_HW_I2C
#else
#define U8G_USES_SW_I2C
#endif
#else
#define U8G_USES_HW_I2C
#define U8G_USES_SW_I2C
#endif

#endif

/**
Expand Down
22 changes: 22 additions & 0 deletions Marlin/src/lcd/dogm/lcdprint_u8g.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 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/>.
*
*/

/**
* @file lcdprint_u8g.cpp
* @brief LCD print api for u8glib
Expand Down
17 changes: 16 additions & 1 deletion Marlin/src/lcd/dogm/marlinui_DOGM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,22 @@ void MarlinUI::init_lcd() {
#endif

#if ANY(MKS_12864OLED, MKS_12864OLED_SSD1306, FYSETC_242_OLED_12864, ZONESTAR_12864OLED, K3D_242_OLED_CONTROLLER)
SET_OUTPUT(LCD_PINS_DC);

#if defined(LCD_PINS_DC) && LCD_PINS_DC != -1
#if IS_I2C_LCD
I2C_TypeDef *i2cInstance1 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SDA_PIN), PinMap_I2C_SDA);
I2C_TypeDef *i2cInstance2 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SCL_PIN), PinMap_I2C_SCL);
const bool isSoftI2C = !(i2cInstance1 && (i2cInstance1 == i2cInstance2)); // Using software I2C driver for LCD
#else
constexpr bool isSoftI2C = false;
#endif
if (!isSoftI2C) SET_OUTPUT(LCD_PINS_DC); // For these LCDs, set as output if not using software I2C driver
#endif

#ifndef LCD_RESET_PIN
#define LCD_RESET_PIN LCD_PINS_RS
#endif

#endif

#if PIN_EXISTS(LCD_RESET)
Expand Down
35 changes: 25 additions & 10 deletions Marlin/src/lcd/dogm/marlinui_DOGM.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,30 @@

//#define ALTERNATIVE_LCD

// Defined DOGLCD_SDA_PIN and DOGLCD_SCL_PIN pins indicate I2C LCD
#if PINS_EXIST(DOGLCD_SDA, DOGLCD_SCL)
#define IS_I2C_LCD 1
#endif

#if ENABLED(REPRAPWORLD_GRAPHICAL_LCD)

// RepRapWorld Graphical LCD

#if HAS_MEDIA
#ifdef __SAMD21__
#define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL
#define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL // 2 stripes, HW SPI (Shared with SD card. Non-standard LCD adapter on AVR.)
#else
// Hardware SPI on DUE
#define U8G_CLASS U8GLIB_ST7920_128X64_4X
#define U8G_CLASS U8GLIB_ST7920_128X64_4X // 2 stripes, SW SPI (Original u8glib device)
#endif
#define U8G_PARAM LCD_PINS_RS
#elif (LCD_PINS_D4 == SD_SCK_PIN) && (LCD_PINS_EN == SD_MOSI_PIN)
// Hardware SPI shared with SD Card
#define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL
#define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL // 2 stripes, HW SPI (Shared with SD card. Non-standard LCD adapter on AVR.)
#define U8G_PARAM LCD_PINS_RS
#else
// Software SPI
#define U8G_CLASS U8GLIB_ST7920_128X64_4X
#define U8G_CLASS U8GLIB_ST7920_128X64_4X // 2 stripes, SW SPI (Original u8glib device)
#define U8G_PARAM LCD_PINS_D4, LCD_PINS_EN, LCD_PINS_RS
#endif

Expand Down Expand Up @@ -126,12 +131,16 @@

// MKS 128x64 (SSD1306) OLED I2C LCD

#define FORCE_SOFT_SPI // SW-SPI

#if ENABLED(ALTERNATIVE_LCD)
#define U8G_CLASS U8GLIB_SSD1306_128X64_2X // 4 stripes
#if IS_I2C_LCD
#define U8G_CLASS U8GLIB_SSD1306_128X64_2X_I2C_2_WIRE // I2C
#define U8G_PARAM U8G_I2C_OPT_NONE
#else
#define U8G_CLASS U8GLIB_SSD1306_128X64 // 8 stripes
#define FORCE_SOFT_SPI // SW-SPI
#if ENABLED(ALTERNATIVE_LCD)
#define U8G_CLASS U8GLIB_SSD1306_128X64_2X // 4 stripes
#else
#define U8G_CLASS U8GLIB_SSD1306_128X64 // 8 stripes
#endif
#endif

#elif ANY(FYSETC_242_OLED_12864, K3D_242_OLED_CONTROLLER)
Expand Down Expand Up @@ -164,7 +173,11 @@
// - or -
// Zonestar SH1106 OLED SPI LCD

#define FORCE_SOFT_SPI // SW-SPI
#if IS_I2C_LCD
#define U8G_PARAM U8G_I2C_OPT_NONE // I2C LCD
#else
#define FORCE_SOFT_SPI // SW-SPI
#endif
#if ENABLED(ALTERNATIVE_LCD)
#define U8G_CLASS U8GLIB_SH1106_128X64_2X // 4 stripes
#else
Expand Down Expand Up @@ -232,6 +245,8 @@
#ifndef U8G_PARAM
#if ENABLED(FORCE_SOFT_SPI)
#define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // SW-SPI
#elif IS_I2C_LCD
#define U8G_PARAM U8G_I2C_OPT_NONE // I2C LCD
#else
#define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // HW-SPI
#endif
Expand Down
Loading