I2C LCD (STM8S005KBT6) from Seeedstudio


I’ve been trying to hook up this LCD but haven’t yet found anything which works. I’ve tried the various iterations of Adafruit GFX and SSD1306 however it would appear this LCD has a different controller, hence requiring different code / porting etc. I see they do have an Arduino library, so I imagine the result I’m looking for is not far off from that… Library Link

This is the unit I’ve got… I2CLCD

Has anyone had any experience with this or have any ideas?



@neal_tommy, that unit is an “intelligent” display which has an onboard controller for graphics commands (eg drawing a line). As such, no other library other than its own will work with it. I’ve looked at the seeedstudio library and it looks relatively easy to port.

I can port the library and examples for you but I suggest taking a crack at it yourself. There are several things to consider which I’ve been discussion with @ScruffR (the great). I’ll let him post that guidance. Post any problems you may have so we can help you then. :wink:


@neal_tommy, as the even greater :sunglasses: @peekay123 mentioned, I’ll take the baton from him, but as I’m just on my way out, I’d have to be short and will elaborate a bit more if needed.

As said it’s straight forward - at least to get it building, testing would require the hardware which we both don’t have.

But there are a few things to get you started with:

  • Replace <Arduino.h> with "Particle.h" as you are not dealing with an Arduino
  • add a #define pgm_read_byte_near(_ptr) *(uint8_t*)_ptr to the header file, as this macro is not defined in the Particle world (yet)
  • you won’t need the #include <Wire.h> and #include <string.h> lines.
  • In the samples whereever you find a “never-ending-loop” place a Particle.process(); line inside these loop (or break the loops)
  • finally you need to add a constructor to the class like this
// ----------------
// in the .h file
class I2C_LCD : public Print

// ----------------
// in the .cpp file
I2C_LCD::I2C_LCD(void) { }

Any further questions, just ask …

1 Like

@ScruffR, @peekay123 … the greats…Thanks to both of you for the quick reply, much appreciated.

I’ll give a bash on the few things mentioned in the last post (I imagine these relate to the existing library, from which the changes should be made?) and see how I get along there. I do imagine I might come stuck upon a few lines however will grind it through and let you know the result or multiple questions!

I’ve got all the hardware so would be happy to get it set up on this side. If the result is good I’ll send some pictures.




All done but no success on the hardware front. I’ve made the change you suggest @ScruffR and at first it compiled but nothing on the screen. I’ve since changed something and it won’t even compile now… so not sure where I diverted from instruction.

I’ve put the code up here, let me know if you can go through it to see where my mistake(s) are.

Old Code and New Code (Modified Folder)


Hmm? For me your code (inside the Modified Code folder) builds just fine.
So you can’t be too wrong then :+1:

What error message do you get?

For the hardware side of things, I don’t know if there are any I2C pull-up resistors on the board (I’d suspect so tho’), but if there aren’t try adding 4k7 (D0->3V3; D1->3V3).
BTW: Have you connected the device to D0/D1 on the Photon?

You can also remove these lines

#include <stdio.h>
#include <inttypes.h>

and this line is only “required” inside the header file

#define pgm_read_byte_near(_ptr) *(uint8_t*)_ptr

I’d also not move Wire.begin() into the constructor, as the sequence in which constructors are called is “unpredictable” which might mean that Wire is not instantiated by the time your constructor wants to call Wire.begin().
Stick with the empty constructor and the LCD_I2C::Init() aproach and instead of calling Wire.begin() explicitly in the sample, just call the Init().

1 Like

@ScruffR @peekay123 Ok, I’ve got it to a stage where it is compiling and all seems well however no action on the hardware side.

Confirmed : the I2C lines both have pull up resistors as per the schematic (a 10K on each line). The unit runs off 5V (so plugged into the Photon) and has it’s own 3V3 regulator so it is sorted on power. I2C lines are plugged into D0 and D1 as per diagrams.

Unsure of :

I see there is a line, which I’ve removed so that it could compile
#include <avr/pgmspace.h>
is there anything in here I need to worry about?

I also edited out this line, and contents below, as this was causing issues

const Font_Info_t fontInfo[I2C_LCD_NUM_OF_FONT] = 

My Photon is breathing green after about a minute of cyan which I understand is showing being disconnected from the cloud, I take it there might not be enough Particle.process(); around.

I’ve updated the changes I’ve made on the Github link in the post above.

Here are some photos of the setup, not rocket science as it is just connect and “play”…

@neal_tommy, does the display do/display anything when you power it up?

The reason the photon is losing cloud connection is that you are not calling Particle.process() in the while(1) loop. The location of the Particle.process() should look like this:

// This #include statement was automatically added by the Particle IDE.
#include "I2C_LCD.h"

uint8_t I2C_LCD_ADDRESS = 0x51; //Device address configuration, the default value is 0x51.

void setup()
    Wire.begin();         //I2C controller initialization.

void loop()
    LCD.CleanAll(WHITE);    //Clean the screen with black or white.
    delay(1000);            //Delay for 1s.

    //8*16 font size��auto new line��black character on white back ground.
    LCD.FontModeConf(Font_6x8, FM_ANL_AAA, BLACK_BAC); 
    LCD.DispStringAt("Hello World!", 0, 10);    //Display "Hello World!" on coordinate of (0, 10).

    while(1) {   //Wait for ever.
      Particle.process();  // This keeps the cloud connection active

If nothing displays then I would start suspecting the library code and some of the timing.

1 Like

Without having looked at your code yet, commenting this

const Font_Info_t fontInfo[I2C_LCD_NUM_OF_FONT] = ...

might also interfere with the use of LCD.DisplayStringAt().
Undefined characters might well be invisible :wink:

What were the problems with having this part included?

Try changing LCD.CleanAll(WHITE) for LCD.CleanAll(BLACK) to see if anything changes.

1 Like


  • Display doesn’t do anything. It shows the factory standard logo and then that fades away. Thereafter nothing.
  • While(1) loop adjusted as per your recommendation.


  • Having this part included produced the following error :

I’ll get back on to this tonight after work and let you know if there is any sign of life from the display! I might also just connect it up to an Arduino, just to confirm that it DOES work…

1 Like

I just saw that this code block is commented out in the original library too, so obviously unneeded :blush:

BTW: Have you tried the other hint?

@ScruffR, @peekay123 … Sorry I’ve been so quiet on this. I’ve spent the evening trying different lines of code from the example however it seems there is some comms issues with the display and the Photon (so no instructions getting through at all).

Will give it a try on the Arduino just now and see how that turns out. I at least want to know that the screen is operational. Thereafter I can relook at the code… some time later… Ok, so it works on Arduino with the original code from Seeedstudio. At least the screen is not a dud, so it’s just in the coding / porting.

Is there any porting that you might be able to do without the hardware, and I’ll test it on my setup here?

1 Like

@neal_tommy, which arduino did you test with. I wonder if there is some I2C timing issues. On a Digole display, sending commands too fast can cause issues. Do you have a logic analyzer to look at the I2C bus?

@peekay123 I tried it out with a Leonardo and it worked first time. I wonder what the timing difference is between the Photon and Leonardo?

Unfortunately I don’t own a logic analyser, so no help there.

Let me know what you think, or if there is another route to follow here. Perhaps there is a basic I2C structure program, with basic send commands, that I could start off from? Or the Digole display code, and perhaps try to work backwards?

@peekay123 @ScruffR This might be a newbie question but is it not something to do with the internal pull up / pull down resistors? I read this this morning and thought it might be effecting operations…

I imagine that the comms across the I2C lines happen at 5V, so perhaps there is something needed to be set here?

I2C communication only relies on the pull-ups for the HIGH level and LOW level is common to 3.3V and 5V devices anyway due to the common ground (which all devices have to share).

The different HIGH levels should just be taken in consideration when choosing the external pull-up resistor values - you can’t use the internal pull-ups for I2C.

Or have you got an oszillograph (or know someone to lend you one)?

For the software side of things, there are some commented Serial.print() statements in the lib. Try to activate them, maybe add some more wherever you suspect possible issues and have a check where things come back different than expected.

You could also try to add this in your setup() line in your lib

void setup()
  Wire.stretchClock(true);  // activate clock stretching
  Wire.setSpeed(50000);  // set 50kHz I2C clock speed
  // Particle.process(); not needed here
1 Like

@ScruffR - Thanks for the ideas here however it seems nothing is changing this at the moment.

I think there might be two routes forward here; one is to “port” the code, which I’m not sure how to do, and the second might be to start from scratch with some sort of basic I2C code… (registering address, send a command, receive a response…).

I found a cool article by Nick which I’ve been reading through… Otherwise I’m stuck here and not sure which direction to take to tackle this … (even the guys who wrote the code for the display have responded saying they cannot help).

Let me know what you think… cheers.

@peekay123 @ScruffR - A small picture for you to help celebrate the success here.

Root cause - although the screen advertised that it indeed had pull up resistors it appears they were left off! So adding some in the whole thing has come alive. Code = 100%, Photon = 100%… screen, eventually = 100%.

Now time to work on the actual project it was meant for!


Sometimes just trying wins over pondering :wink:

Congrats to your win over the matter :+1:

1 Like