lovyan03 / LovyanGFX

SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51)
Other
1.03k stars 189 forks source link

Request for implementing ESP8266 support #130

Closed ESPboy-edu closed 1 year ago

lovyan03 commented 2 years ago

@ESPboy-edu You must first learn how to say hello.

To be honest, I'm not interested. I think you need to present me with the benefits.

jicehel commented 2 years ago

Hello, Bonjour and こんにちは @lovyan03

First sorry for my english level as i'm french. I would just add some words about Roman's request. He done a console based on ESP8266 so as your library is very good and works for the big brother of the ESP 8266 we would be able to use all the power and functions of your library. I think that Roman thought that the request had to kept light and small. As you see i don't ask for changes often so maybe i don't make it as it's should be done but i'll be happy to answer your questions (if i can).

Have a good day, Bonne journée, 良い一日を過ごしてください

tobozo commented 2 years ago

Hello Jean-Charles and merci pour le feedback ;)

The problem is with pgm_read_bytes, since ESP8266 can't seamlessly mix ram and irom like ESP32 does, adding PROGMEM support to LGFX would require logic branching about everywhere in the code and make the project impossible to maintain.

Please tell me you know a solution for that so that I can remove the wontfix tag ;)

jicehel commented 2 years ago

Thanks for your answer and explanations Tobozo

I'm not very good in this technology, so i'll let Roman or Steph answer if they have any idea or solution. Thanks again, i'll continue to read exchanges but i can't give you a good answer and propose good solution i hope that others will be able to do it.

ESPboy-edu commented 2 years ago

Hello @lovyan03 )

You don't have to say "hello" to me, honestly if you don't want or you want your text to be shorter.

Your library is really great. A fantastic amount of work done. People say it is much faster than the TFT_eSPI which I have always used, but I have not tested this yet. First, I'll try to figure out if this is so. I see you have already explained that it is not an easy thing to add PROGMEM support and I understand. I and a few other enthusiasts are engaged in an educational project www.espboy.com, which is built on ESP8266 and we thought it would be great to be able to use your wonderful library when developing software and games for ESPboy. Regarding the problems with PROGMEM, in the latest version of Arduino ESP8266 SDK I see the setting in the IDE which is called "byte/word access to IRAM/PROGMEM" or "Use pgm_read macros for IRAM/PROGMEM". Perhaps this setting solves the problem of using "PROGMEM" and makes work on ESP8266 with flash memory as simple as in ESP32. I'll test it this week.

Forgive me for the short request at the very beginning, which you thought was not polite. I really should be more attentive to words, especially when I come to someone else's house and ask for something. My mistake and apologies.

With respect, Roman

tobozo commented 2 years ago

@ESPboy-edu nice tip, is that the option?

image

ESPboy-edu commented 2 years ago

Hello, @tobozo ! Yes, you are absolutely right. I discovered this option a few days ago and have to test it deeper. But I suppose it can solve PROGMEM problem, but the note "very slow" still need investigation )

tobozo commented 2 years ago

Please have a look at the developer branch, there's a configuration fixture tested with Hardware SPI

:warning: Until this is stable, you will need to delete the /src/lgfx/v0* files/folders in order to compile a sketch.

lovyan03 commented 2 years ago

@ESPboy-edu @Jicehel Hello. Thank you for your patience. The develop branch has been updated, please help us to test it on ESP8266. Please adjust the file src/lgfx_user/LGFX_ESP8266_sample.hpp to your environment and try the following source code. Please let me know if you have any problems.

#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <lgfx_user/LGFX_ESP8266_sample.hpp>

LGFX display;

void setup(void)
{
  display.init();

  display.drawString("Hello ESP8266!", 0, 0);
}

void loop(void)
{
  static int count;
  count++;
  display.drawCircle(display.width()>>1, display.height()>>1, count & 127, count);
}
tobozo commented 2 years ago

thanks for the fabulous work :+1:

I can't get the ST7789 to work with d-duino-v6.

Apparently the original driver isn't using hardware spi, and this display has no CS pin broken out.

I have experimented different settings without success and I'm out of ideas.

/*
Display model : ST7789 1.3" Screen
TFT_SDA(MOSI): GPIO 4
TFT_SCL/SCK:   GPIO 5
TFT_DC:        GPIO 0
TFT_RST:       GPIO2
TFT_LED :      GPIO16
*/
class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_ST7789 _panel_instance;
  lgfx::Bus_SPI      _bus_instance;

 public:

  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();
      cfg.spi_mode   = 3;
      cfg.freq_write = 40000000;
      cfg.freq_read  = 16000000;
      cfg.pin_sclk   = 5;
      cfg.pin_mosi   = 4;
      cfg.pin_miso   = -1;
      cfg.pin_dc     = 0;
      //cfg.spi_host   = 1;
      _bus_instance.config(cfg);
      _panel_instance.setBus(&_bus_instance);
    }

    {
      auto cfg = _panel_instance.config();
      cfg.pin_cs           =    -1;
      cfg.pin_rst          =     2;
      cfg.pin_busy         =    -1;
      cfg.memory_width     =   240;
      cfg.memory_height    =   320;
      cfg.panel_width      =   240;
      cfg.panel_height     =   240;
      cfg.offset_x         =     0;
      cfg.offset_y         =     0;
      cfg.offset_rotation  =     0;
      cfg.dummy_read_pixel =     8;
      cfg.dummy_read_bits  =     1;
      cfg.readable         = false;
      cfg.invert           = true;
      cfg.rgb_order        = false;
      cfg.dlen_16bit       = false;
      cfg.bus_shared       = true;
      _panel_instance.config(cfg);
    }
    setPanel(&_panel_instance);
  }
};
lovyan03 commented 2 years ago

@tobozo I don't want to implement software SPI because it is hard to do.

tobozo commented 2 years ago

ok I'll use an ILI9341 and post feedback here

does this mean d-duino-v6 can't do hardware spi at all ? it seems to be reusing SDA/SCL pins

tobozo commented 2 years ago

got two displays working so far \o/

Wemos Mini D1 + TFT 1.4 Shield

#define TFT_MISO    D6
#define TFT_CS      D4
#define TFT_MOSI    D7
#define TFT_SCK     D5
#define TFT_DC      D3
#define TFT_RST     D1
#define TFT_LED     -1

class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_ST7735S _panel_instance;
  lgfx::Bus_SPI       _bus_instance;

 public:

  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();
      cfg.spi_mode   = 0;
      cfg.freq_write = 40000000;
      cfg.freq_read  = 16000000;
      cfg.pin_sclk   = TFT_SCK;
      cfg.pin_mosi   = TFT_MOSI;
      cfg.pin_miso   = TFT_MISO;
      cfg.pin_dc     = TFT_DC;
      //cfg.spi_host   = -1;
      _bus_instance.config(cfg);
      _panel_instance.setBus(&_bus_instance);
    }
    {
      auto cfg = _panel_instance.config();
      cfg.pin_cs           = TFT_CS;
      cfg.pin_rst          = TFT_RST;
      cfg.pin_busy         =    -1;
      cfg.memory_width     =   132;
      cfg.memory_height    =   162; // 162 or 160 or 132
      cfg.panel_width      =   128;
      cfg.panel_height     =   128;
      cfg.offset_x         =     2;
      cfg.offset_y         =     1;
      cfg.offset_rotation  =     0;
      cfg.dummy_read_pixel =     8;
      cfg.dummy_read_bits  =     1;
      cfg.readable         = true;
      cfg.invert           = false;
      cfg.rgb_order        = false;
      cfg.dlen_16bit       = false;
      cfg.bus_shared       = true;
      _panel_instance.config(cfg);
    }
    setPanel(&_panel_instance);
  }
};

Wemos Mini D1 + LoLin TFT-2.4 Shield:


#define TFT_MISO    D6
#define TFT_CS      D0
#define TFT_MOSI    D7
#define TFT_SCK     D5
#define TFT_DC      D8
#define TFT_RST     D1
#define TFT_LED     -1

class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_ILI9341 _panel_instance;
  lgfx::Bus_SPI       _bus_instance;

 public:

  LGFX(void)
  {
    {
      auto cfg = _bus_instance.config();
      cfg.spi_mode   = 0;
      cfg.freq_write = 80000000;
      cfg.freq_read  = 16000000;
      cfg.pin_sclk   = TFT_SCK;
      cfg.pin_mosi   = TFT_MOSI;
      cfg.pin_miso   = TFT_MISO;
      cfg.pin_dc     = TFT_DC;
      //cfg.spi_host   = -1;
      _bus_instance.config(cfg);
      _panel_instance.setBus(&_bus_instance);
    }
    {
      auto cfg = _panel_instance.config();
      cfg.pin_cs           = TFT_CS;
      cfg.pin_rst          = TFT_RST;
      cfg.pin_busy         =    -1;
      cfg.memory_width     =   240;
      cfg.memory_height    =   320;
      cfg.panel_width      =   240;
      cfg.panel_height     =   320;
      cfg.offset_x         =     0;
      cfg.offset_y         =     0;
      cfg.offset_rotation  =     0;
      cfg.dummy_read_pixel =     8;
      cfg.dummy_read_bits  =     1;
      cfg.readable         = true;
      cfg.invert           = false;
      cfg.rgb_order        = false;
      cfg.dlen_16bit       = false;
      cfg.bus_shared       = true;
      _panel_instance.config(cfg);
    }
    setPanel(&_panel_instance);
  }
};
m1cr0lab commented 2 years ago

@lovyan03

Thank you so much for this great library, the quality of your work and your responsiveness. I don't know how you manage to always find an efficient solution to the many questions that are submitted to you, and at the same time manage to keep your library stable. Congratulations for these feats!

@tobozo

Merci infiniment :wink: for your precious help and your availability to help @lovyan03. Thank you very much for these configuration examples. I guess they will help a lot.

@ESPboy-edu will probably get back to you as soon as he can. As for me, I don't have an ESPboy on hand to test yet, but I should get one in not too long. Nevertheless, I am quite confident since it is controlled by a Wemos D1 Mini (like the MCU you tested) and it has a TFT ST7735 screen. Your configuration files will help us a lot on how to set things up.

Thanks again to both of you for your very valuable help.

lovyan03 commented 2 years ago

@ESPboy-edu @Jicehel @m1cr0lab @tobozo A new release has been created. The SPI of ESP8266 is now available in the v1 specification. It does not support DMA transfer yet, but you can try it anyway.

tobozo commented 2 years ago

https://user-images.githubusercontent.com/1893754/125471709-219fa1d4-3ef4-4241-916b-493d7449cc08.mp4

m1cr0lab commented 2 years ago

Thank you for this very convincing demo @tobozo. I can't wait to get my ESPboy to test this myself. And thanks again to @lovyan03 for adding this possibility!

robertoetcheverryr commented 2 years ago

Hello All, Thanks for the effort to add ESP8266 support. From what I understand from the conversation, the experimental support for ESP8266 depends on setting the 「Byte/Word access to IRAM/PROGMEM (very slow)」option on the IDE, is that correct? I have an ESP8266 board and an SPI ILI9841 Display on which to test. I will be downloading the dev branch tomorrow to test. Are there any particular tests that would be useful for me to run or report upon?

lovyan03 commented 2 years ago

@robertoetcheverryr Hello, Thank you for your cooperation. ESP8266 support is now also included in the released version.

robertoetcheverryr commented 2 years ago

@lovyan03 Thank you! I have just tested it with the currently available version for the Arduino IDE and it indeed works using hardware SPI. Feel free to ping me if you implement u8g2/vlw/DMA and you need somebody to test it. For now, I'm delving into the examples and code, it works both for learning the code AND it forces me to finally practice my kanji reading. Once again, thanks for your work.

m1cr0lab commented 2 years ago

@lovyan03 @tobozo, hello to you both.

I finally got my ESPboy, and I just started testing with LovyanGFX. The screen is an ST7735 1,44" 128x128. I started from the configuration proposed by @tobozo, which I slightly adapted as follows:

#define LGFX_USE_V1
#include <LovyanGFX.h>

constexpr uint8_t TFT_MISO = D6; // GPIO 12
constexpr uint8_t TFT_CS   = -1; // wired to an MCP23017 with LOW level
constexpr uint8_t TFT_MOSI = D7; // GPIO 13
constexpr uint8_t TFT_SCK  = D5; // GPIO 14
constexpr uint8_t TFT_DC   = D0; // GPIO 16
constexpr uint8_t TFT_RST  = -1;
constexpr uint8_t TFT_LED  = -1; // wired to an MCP4725

constexpr uint8_t TFT_WIDTH  = 128;
constexpr uint8_t TFT_HEIGHT = 128;

class LGFX : public lgfx::LGFX_Device {

    lgfx::Panel_ST7735S _panel_instance; // Panel_ST7735 doesn't work...
    lgfx::Bus_SPI       _bus_instance;

    public:

        LGFX(void) {

            {
                auto cfg = _bus_instance.config();

                cfg.spi_mode   = 0;
                cfg.freq_write = 39999999; // 40000000 gives me a weird thing
                cfg.freq_read  = 20000000;
                cfg.pin_sclk   = TFT_SCK;
                cfg.pin_mosi   = TFT_MOSI;
                cfg.pin_miso   = TFT_MISO;
                cfg.pin_dc     = TFT_DC;

                _bus_instance.config(cfg);
                _panel_instance.setBus(&_bus_instance);
            }

            {
                auto cfg = _panel_instance.config();

                cfg.pin_cs           = TFT_CS;
                cfg.pin_rst          = TFT_RST;
                cfg.pin_busy         = -1;
                cfg.memory_width     = 132;
                cfg.memory_height    = 132;
                cfg.panel_width      = TFT_WIDTH;
                cfg.panel_height     = TFT_HEIGHT;
                cfg.offset_x         = 2;
                cfg.offset_y         = 1;
                cfg.offset_rotation  = 2;
                cfg.dummy_read_pixel = 8;
                cfg.dummy_read_bits  = 1;
                cfg.readable         = true;
                cfg.invert           = false;
                cfg.rgb_order        = false;
                cfg.dlen_16bit       = false;
                cfg.bus_shared       = true;

                _panel_instance.config(cfg);
            }

            setPanel(&_panel_instance);

        }
};

The rendered display is correct.

On the other hand, by replacing :

cfg.freq_write = 39999999;

with:

cfg.freq_write = 40000000;

It seems to render much faster, but I get a vertical offset:

Demo

The top edge of the rectangle disappears, and the bottom edge has a double thickness.

I tried to correct this by testing different values for cfg.offset_y, but nothing seems to work. No matter what value is assigned, I can never get everything to fit properly into the screen frame.

Regarding the cfg.freq_write property, the following value :

cfg.freq_write = 39999999;

gives me exactly the same as with :

cfg.freq_write = 27000000;

Yet, a 40 MHz frequency seems to work overall, with much faster rendering, but I have this vertical offset that I can't get right.

I tried to compile my project with ESP8266's frequencies at 80 MHz and 160 MHz. But I don't get any difference either.

Do you have any idea of what I could do to get it right?

I thank you in advance for any improvement that would seem obvious to you.

PS: @tobozo, on your video, it seems that you get the same offset as I do. Look carefully at the last line of pixels...

lovyan03 commented 2 years ago

@m1cr0lab Thanks for the report ! The SPI clock can be 80MHz divided by an integer. In other words, 39.99MHz will be rounded to 26.67MHz.

The reason for the offset is probably that the initialization command sequence is not being interpreted correctly and VerticalScroll is being executed incorrectly.

Try running this after drawing a shape on the screen.

lcd.startWrite();
lcd.writeCommand(0x37); // VSCROLL command
lcd.writeData16( 0 );     // scroll start addr
lcd.endWrite();

If it is not displayed in the correct position, try changing the argument of the function writeData16.

m1cr0lab commented 2 years ago

Bingo!

@lovyan03 You're awesome!

These are the settings that work:

cfg.freq_write = 40000000;

cfg.memory_width  = 132;
cfg.memory_height = 132;
cfg.panel_width   = 128;
cfg.panel_height  = 128;
cfg.offset_x      = 2;
cfg.offset_y      = 0;

With your trick at the end of the draw function:

lcd.startWrite();
lcd.writeCommand(0x37); // VSCROLL command
lcd.writeData16(1);     // scroll start addr
lcd.endWrite();

And so we have a better rendering speed.

But then, do you think the problem can be solved in your library? Or do I have to systematically add this piece of code?

Anyway, thanks a lot for your precious help.

By the way, how should I set cfg.freq_read?

Many examples use this:

cfg.freq_read = 16000000;

But @ESPboy-edu, who uses TFT_eSPI, sets it like this:

cfg.freq_read = 20000000;

Sorry for my ignorance in this area...

Thank you very much for everything @lovyan03. And thanks to @tobozo who gave us a good configuration as a starting point. Regards, Steph

lovyan03 commented 2 years ago

@m1cr0lab Inputting SPI 40MHz to the ST7735 is well beyond the guaranteed operating range. According to the specification, the minimum serial clock cycle is as follows

In other words, the maximum frequency is as follows

It would not be surprising if the operation was not correct when communicating at frequencies higher than this. In my experience, there are many cases where the ST7735 series cannot keep up with 40MHz, so I keep it to 27MHz at the highest.

Regarding the setting of the readout clock value, it is best to judge whether the result of the actual pixel readout is correct or not. It is easy to see how to use copyRect as in the following example.

for (int i = 0; i < 256; ++i)
{
  lcd.fillRect((i * lcd.width()) >> 8,  0, 2, 16, lcd.color888(i, 0, 0));
  lcd.fillRect((i * lcd.width()) >> 8, 16, 2, 16, lcd.color888(0, i, 0));
  lcd.fillRect((i * lcd.width()) >> 8, 32, 2, 16, lcd.color888(0, 0, i));
  lcd.fillRect((i * lcd.width()) >> 8, 48, 2, 16, lcd.color888(i, i, i));
}
for (int i = 0; i < 100; ++i)
{
  lcd.copyRect(0, 1, lcd.width(), lcd.height()-1, 0, 0);
}

If it is set correctly, it will simply scroll. If the clock is too fast or the dummy read is not correct, the color will change.

m1cr0lab commented 2 years ago

@lovyan03 Thank you so much for your help and your clear explanation. I will test your example with copyRect() soon.

I wish you a good evening. Steph

lovyan03 commented 2 years ago

@m1cr0lab Wow... I greatly appreciate the sponsorship you have given me…!

m1cr0lab commented 2 years ago

@lovyan03 You really deserve it!

m1cr0lab commented 2 years ago

Hello @lovyan03,

Sorry to bother you again, but I found a problem with the pushImage() function and the transparency color.

When I set an image like this (with a transparency color equal to 0xf81f) :

const uint16_t IMAGE_COLORMAP[] = { 0x1ff8, 0xfe40, ...  };

And I display it like this:

sprite.pushImage(x, y, w, h, IMAGE_COLORMAP, 0xf81f);

Everything works normally and the image is displayed correctly, with transparent pixels.

However, when I set the image with PROGMEM to host the data on the Flash memory of the ESP8266:

const uint16_t IMAGE_COLORMAP[] PROGMEM = { 0x1ff8, 0xfe40, ...  };

In this case, the microcontroller systematically crashes.

The problem only occurs when you specify a transparency color with pushImage(), otherwise everything works fine, even when using PROGMEM.

Is this related to the issues raised above about PROGMEM? Is there a way to solve this? Maybe it's an issue in the fixes you made to your library (did you remember to check that everything works normally with PROGMEM when specifying a transparency color)?

I thank you in advance for your opinion on the matter. Regards, Steph

lovyan03 commented 2 years ago

@m1cr0lab Thanks for the report. The "develop" branch has been modified. Some pixel format conversion functions now go through the "pgmread" function.

This fix will probably avoid the problem you are facing now.

However, since there are dozens of functions that need to be addressed, we need to make the same fix for all of them, and it will take some more time to fully address them. Also, processing images in RAM that do not originally require pgmread will slow things down a bit, so we need to look into other ways to deal with this.

The same problem has also been found to occur with each image format data such as JPG, PNG, BMP, etc. placed on the ROM.

m1cr0lab commented 2 years ago

Thanks for trying something @lovyan03! But it doesn't compile anymore... And this, whether I use PROGMEM or not.

Here is the compilation log

I don't know what to tell you, I'm sorry 😕

lovyan03 commented 2 years ago

@m1cr0lab Oops... Sorry, it was incomplete. I've fixed it so that it doesn't give an error now, so please try again. You will get a little warning, but you should be able to build it.

m1cr0lab commented 2 years ago

Thank you for fixing it @lovyan03. Nevertheless, there is still strange behavior...

When I set:

const uint16_t TRANS_COLOR PROGMEM = 0xf81f;
const uint16_t SPRITE_1[]  PROGMEM = { ... };
const uint16_t SPRITE_2[]  PROGMEM = { ... };

Then this works: 🙂

fb.pushImage(x1, y1, w1, h1, SPRITE_1, TRANS_COLOR);

But this crashes: 👀

fb.pushImage(x1, y1, w1, h1, SPRITE_1, TRANS_COLOR);
fb.pushImage(x2, y2, w2, h2, SPRITE_2, TRANS_COLOR);

Weird...

lovyan03 commented 2 years ago

@m1cr0lab You have placed the TRANS_COLOR in the PROGMEM. Therefore, you need to write the following...

fb.pushImage(x1, y1, w1, h1, SPRITE_1, pgm_read_word(&TRANS_COLOR));

or without PROGMEM and set as follows.

static constexpr const uint16_t TRANS_COLOR = 0xf81f;

I don't know the exact reason, but if you are using TRANS_COLOR in one place, it was probably embedded directly into the PROGMEM without being placed there by compiler optimisation.

m1cr0lab commented 2 years ago

... Sorry for this beginner's mistake. 😁

It's the first time I've had to deal with PROGMEM, and I don't have the right habits yet...

It works much better now. 🙂

Thanks again for your help @lovyan03!

lovyan03 commented 2 years ago

@m1cr0lab @tobozo @Jicehel @ESPboy-edu I've just updated the develop branch with some significant performance improvements for the ESP8266, so please give it a try.

m1cr0lab commented 2 years ago

Thank you very much @lovyan03!

Here is a demo of what I get (the latest commit is on the right):

https://user-images.githubusercontent.com/31308530/130987312-7b117aa0-9958-4d57-b26d-4d9915c65e38.mp4

The SPI bus is clocked at 26.67 MHz for this demo (which does not work well at 40 MHz).

With my Pong demo, the range is as follows, depending on the number of objects on the screen:

SPI is also clocked at 26.67 MHz and I send a full buffer (128x128) for each frame.

Does it match the improvements you expected?

tobozo commented 2 years ago

@m1cr0lab adding this in the setup() after tft.init() while using cfg.offset_y=2 was enough to get the display running without the glitchy bottom line at 40MHz

  tft.init();
  #if SPI_FREQ_W >= 40000000
    // ST7735 40MHz overclocking tradeoff: vscroll init setting needs to be replayed
    tft.startWrite();
    tft.writeCommand(0x37); // VSCROLL command
    tft.writeData16(1);     // scroll start addr
    tft.endWrite();
  #endif
m1cr0lab commented 2 years ago

@tobozo thank you for this tip!

You gonna laugh... I thought I had to send this command at each loop() 😂 Sorry... I don't have your experience 😁 And @lovyan03 advised me to run this command after each draw. But, indeed, it seems to work by running it only once in the setup().

However, the vertical offset that works well for me is:

cfg.offset_y = 0;  // not 2

Well in any case thank you very much for your insights.

lovyan03 commented 2 years ago

@m1cr0lab Hmmm. The performance was not as good as I expected. Probably I made a mistake.

After publishing the develop branch previously, I carefully re-implemented the PROGMEM support. This resulted in a significant performance degradation. But I had not published that version. This means that I got stability in exchange for performance when no one was looking, and then recovered the performance while maintaining the stability. I'm sorry for getting your hopes up.

I've now updated the develop branch again. It may slightly improve the speed when transferring images.


Sorry about that. I didn't accurately convey my intentions regarding the scroll amount setting.

I wanted you to "change VSCROLL with some picture displayed and see the difference" in order to determine if the amount of VSCROLL was appropriate. It is sufficient to set VSCROLL only once the first time.

I apologise again and hope this helps.

tobozo commented 2 years ago

@lovyan03 There's no need to apologize, your work is very much appreciated, and getting stability in exchange for performance is a good tradeoff.

https://twitter.com/TobozoTagada/status/1431210936564654080

Thanks again for your patience and kindess.

m1cr0lab commented 2 years ago

@lovyan03

I completely agree with @tobozo. You don't need to apologize at all! I am very happy with the performance obtained thanks to your work. The rendering is really smooth and gives the possibility to do very nice things with the ESPboy.

I'm sorry I misunderstood your hints to set the VSCROLL...

Thanks again to you and @tobozo. Your help has been invaluable.

lovyan03 commented 2 years ago

@m1cr0lab @tobozo @Jicehel @ESPboy-edu The develop branch has been updated to allow I2C with ESP8266.

I bought an ESPboy2 and made some adjustments on the actual device. I've added a configuration example, if you're interested. ( https://github.com/lovyan03/LovyanGFX/blob/develop/src/lgfx_user/LGFX_ESPboy.hpp ) Backlight control is now possible. Also, since CS control is now available, pixel readout is now possible.

The write frequency is set to 40MHz, but it seems to work fine for now.

jicehel commented 2 years ago

@lovyan03

Hello. I just write some words: I don't comment each time as i can't test atm for different raisons but @m1cr0lab do it for us, but many thanks lovyan03 for this works and these infos. Very good news. I hope to be able to see all these change soon too.

m1cr0lab commented 2 years ago

Fantastic! Thank you soooooooo much @lovyan03 for your involvement. I'm at work right now, but I'll test this as soon as I can. You are really brilliant!

m1cr0lab commented 2 years ago

Hi @lovyan03,

The brightness setting works perfectly. Thank you very much for this.

However, it seems that something goes wrong when you overclock the SPI bus to 40 MHz and draw directly on the screen (whereas if you prepare the drawing in a sprite before sending it to the screen everything goes fine):

#include "LGFX_ESPboy.hpp"

static constexpr uint32_t BRIGHTNESS_MIN = 32;
static constexpr uint32_t BRIGHTNESS_MAX = 128;

LGFX tft;

void setup() {

    tft.init();

    tft.startWrite();
    tft.writeCommand(0x37);
    tft.writeData16(1);
    tft.endWrite();

    // it doesn't display correctly when doing this:
    tft.drawRect(0, 0, 128, 128, 0xfe60);

    // while everything is fine doing it like this:
    // LGFX_Sprite sprite(&tft);
    // sprite.createSprite(128, 128);
    // sprite.drawRect(0, 0, 128, 128, 0xfe60);
    // sprite.pushSprite(0, 0);
    // sprite.deleteSprite();

}

void loop() {

    static uint32_t t = millis();
    static uint8_t  d = 1;
    static uint8_t  b = BRIGHTNESS_MIN;

    uint32_t now = millis();

    if (now - t > 9) {

        tft.setBrightness(b);

        if (d) if (b < BRIGHTNESS_MAX) b++; else d = 0;
        else   if (b > BRIGHTNESS_MIN) b--; else d = 1;

        t = now;

    }

}

https://user-images.githubusercontent.com/31308530/132936969-ade24442-c021-4512-86de-31e27376cec6.mp4

At 26.67 MHz everything is fine though.

Do you have an idea?

lovyan03 commented 2 years ago

@m1cr0lab Hmmm, I have no idea other than to lower the clock. Perhaps it is a difference in marginal performance due to individual differences. The ESPboy2 I got is drawing fine with the sample code you presented. There is no need to adjust the vertical scrolling. To be safe, I will lower the clock in the example setup.

https://user-images.githubusercontent.com/42724151/132938595-332b6b93-418a-4803-a56c-0c70a6b546f8.mp4

m1cr0lab commented 2 years ago

Okay, I see. Thanks for the test @lovyan03.

Your ESPboy is from the last batch. Mine is older. Maybe I had bad luck? I started a poll on the Discord. I hope to get some answers...

I ordered a second one at the same time as you, but I haven't received it yet. Japan is certainly better served than Reunion island. 😁

Anyway, many thanks for your configuration file which includes the brightness setting.

lovyan03 commented 2 years ago

I added the ESP8266 auto-detection feature and updated the Develop branch. Currently, only ESPboy is detected, but the number of supported models may be increased in the future. This makes it possible to draw an ESPboy LCD by simply writing the following There is no need for users to write their own settings.

#define LGFX_AUTODETECT  // or #define LGFX_ESPBOY

#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

LGFX lcd;

void setup (void)
{
  lcd.init();

  /// you can use LGFX
  lcd.fillRect(10,10,10,10,TFT_BLUE);
}
m1cr0lab commented 2 years ago

@lovyan03 Works like a charm! 🙂 Much appreciated. Thanks for your time.

m1cr0lab commented 2 years ago

Hi @lovyan03,

I hope you are well.

I am encountering a quirk with LovyanGFX when using the pushImage() method with data hosted by PROGMEM.

I specify that I work with the commit 8f281eab7adad3c90c89347be1b567bcadca4187.

When the abscissa of the sprite is odd, the MCU crashes. Everything is fine with ordinates though.

In the same way, if the width of the sprite is odd, I get a crash too.

Here is a piece of code that highlights the problem when SIZE or SPEED is odd.

#define LGFX_ESPBOY
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>
#include <Adafruit_MCP23X17.h>

constexpr uint8_t TFT_WIDTH  = 128;
constexpr uint8_t TFT_HEIGHT = 128;

constexpr uint16_t SPRITE_8x8[] PROGMEM = {

    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f,
    0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f, 0xe08f

};

struct Sprite {
    static constexpr uint8_t SIZE  = 8;
    static constexpr uint8_t SPEED = 1;
    int8_t x;
    int8_t y;
    Sprite() : x((TFT_WIDTH - SIZE) >> 1), y((TFT_HEIGHT - SIZE) >> 1) {}
} sprite;

Adafruit_MCP23X17 mcp;
LGFX tft;
LGFX_Sprite fb(&tft);

void setup() {

    // buttons
    mcp.begin_I2C();
    for (uint8_t i=0; i<8; ++i) mcp.pinMode(i, INPUT_PULLUP);

    // graphics
    tft.init();
    fb.createSprite(TFT_WIDTH, TFT_HEIGHT);

}

void loop() {

    uint8_t read_buttons = ~(mcp.readGPIOAB() & 0xff);
    if (read_buttons & 0x1) sprite.x -= sprite.SPEED;
    if (read_buttons & 0x8) sprite.x += sprite.SPEED;
    if (read_buttons & 0x2) sprite.y -= sprite.SPEED;
    if (read_buttons & 0x4) sprite.y += sprite.SPEED;

    fb.fillSprite(0);

    //   it crashes when x is odd
    //              |
    //              v
    fb.pushImage(sprite.x, sprite.y, sprite.SIZE, sprite.SIZE, SPRITE_8x8);
    //                                     ^
    //                                     |
    //                            or when width is odd

    fb.pushSprite(0, 0);

}

Do you have any idea where it came from?

I suppose other methods may be involved if they rely on the same dysfunction...

If you have a little time to check this out, that would be great. Thank you in advance.