Print text at any Y-value on SSD1306?

I'm attempting to print several rows of text, at certain Y-values, on an SSD1306 128x64 LCD display.

I'm using the ssd1306 library by Alexey Dynda. I initially wanted to use the more common LCD libraries out there, such as the Adafruit SSD1306 LCD library, however it unfortunately does not appear I can set custom I2C pins for most such libraries out there, which is required as I'm using a custom board with an ESP32-WROOM-DA chip. The ssd1306 by Dynda appears to be able to do so.

I have the following example code, which prints 6 lines of text:

#include "ssd1306.h"
#include "nano_gfx.h"

const int PIN_I2C_SCL = 16;
const int PIN_I2C_SDA = 13;

void LCDTextDraw(int x, int y, const char* text)
{
  EFontStyle fontStyle;
  
  ssd1306_printFixed(x, y, text, fontStyle);
}

void LCDRectDraw(int x, int y, int w, int h)
{
  ssd1306_fillRect(x, y, x + w, y + h);
}

void LCDScreenClear(bool fill)
{
  ssd1306_clearScreen();

  if (fill)
    LCDRectDraw(0, 0, 128, 64);
}

void LCDInit()
{
  ssd1306_setFixedFont(ssd1306xled_font6x8);
  ssd1306_128x64_i2c_initEx(PIN_I2C_SCL, PIN_I2C_SDA, 0);
}

void setup() 
{
  Serial.begin(9600);

  pinMode(PIN_I2C_SCL, OUTPUT);
  pinMode(PIN_I2C_SDA, OUTPUT);

  LCDInit();
  LCDScreenClear(true);

  LCDTextDraw(30, 0, "TEST 1");
  LCDTextDraw(30, 10, "TEST 2");
  LCDTextDraw(30, 20, "TEST 3");
  LCDTextDraw(30, 30, "TEST 4");
  LCDTextDraw(30, 40, "TEST 5");
  LCDTextDraw(30, 50, "TEST 6");
}

void loop() 
{}

With which I wish to print out 6 lines of text, each line evenly vertically spaced out by 10 pixels.

Which produces the following output on my LCD:

As you can see, the text rows are not evenly vertically spaced out as I wish them to be, with a large space between the TEST 4 and TEST 5 strings.

After looking at the definition of the ssd1306_printFixed function I'm using to print out my text in the example above, it turns out that it can only print rows of text at certain fixed Y-positions:

@warning ssd1306_printFixed() can output chars at fixed y positions: 0, 8, 16, 24, 32, etc.
         If you specify [10,18], ssd1306_printFixed() will output text starting at [10,16] position.

Hence, I also tried using the ssd1306_print function (which uses a cursor to delineate it's printing location on the screen), which doesn't have that warning in it's header declaration. I replaced my LCDTextDraw function with:

void LCDTextDraw(int x, int y, const char* text)
{
  ssd1306_setCursor8(x, y);
  ssd1306_print(text);
}

However, that still produced the exact same output on my LCD, with the same spacing issues.

What is the proper way to print text rows at any Y-value on an LCD?

Thanks for reading my post, any guidance is appreciated.

I would start by verifying that the mapping of screen coordinates to pixels is linear, and that you can draw straight, diagonal lines from one corner to the other. Or, just print one line of text, starting at successive Y pixel coordinates and see if there is a break.

however it unfortunately does not appear I can set custom I2C pins for most such libraries out there

The Adafruit library does not use pin numbers for I2C. It calls the Wire library, so I don't see why that should be an issue.

You can select almost any pins for i2c on ESP32 like this:

Wire.begin(I2C_SDA, I2C_SCL); // replace with the pins you want to use

With the Adafruit library, you can use this constructor:

Adafruit_SSD1306(128, 64, &Wire);

It should then pick up the pins you are using.

Turns out using the Adafruit SSD1306 library is much easier than I first thought, thanks to replies from @jremington and @PaulRB. One just must specify the I2C pins used with Wire, and pass it as reference to the Adafruit_SSD1306 constructor. Additionally, the Adafruit library doesn't appear to have the uneven vertical spacing issue.

The equivalent code below using the Adafruit library:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const int PIN_I2C_SCL = 16;
const int PIN_I2C_SDA = 13;

Adafruit_SSD1306 LCD(128, 64, &Wire);

void LCDTextDraw(int x, int y, const char* text, byte size)
{
  LCD.setCursor(x, y);
  LCD.setTextSize(size);
  LCD.print(text);
  LCD.display();
}

void LCDRectFill(int x, int y, int w, int h, int color)
{
  LCD.fillRect(x, y, w, h, color);
}

void LCDScreenClear(bool fill)
{
  LCD.clearDisplay();
  LCD.display();
  LCD.setTextColor(WHITE, BLACK);

  if (fill)
    LCDRectFill(0, 0, 128, 64, 1);
}

void LCDInit()
{
  LCD.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void setup() 
{
  Serial.begin(9600);
  
  pinMode(PIN_I2C_SCL, OUTPUT);
  pinMode(PIN_I2C_SDA, OUTPUT);

  Wire.setPins(PIN_I2C_SDA, PIN_I2C_SCL);
  Wire.begin();

  LCDInit();
  LCDScreenClear(true);

  LCDTextDraw(30, 0, "TEST 1", 1);
  LCDTextDraw(30, 10, "TEST 2", 1);
  LCDTextDraw(30, 20, "TEST 3", 1);
  LCDTextDraw(30, 30, "TEST 4", 1);
  LCDTextDraw(30, 40, "TEST 5", 1);
  LCDTextDraw(30, 50, "TEST 6", 1);
}

void loop() 
{}

Now produces the desired result:

V76dEm

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.