-
Notifications
You must be signed in to change notification settings - Fork 285
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
Add support for SSD1680 e-paper controller #210
base: master
Are you sure you want to change the base?
Conversation
The driver is based on the construction of IL3820 (SSD1608), which is very similar from command point of view. It is tested on ESP32-S2 MCU and GoodDisplay GDEY029T94.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! Any chance you could share the setup necessary for LVGL? The display is filled with random dots (landscape or portrait) and the label is shown as a black strip while the text appears ghosted (and inverted) on another portion of the display. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
I had the same issue at first.
This is my default lvl config, which should make it work:
# LVGL configuration
#
CONFIG_LV_USE_USER_DATA=y
CONFIG_LV_COLOR_DEPTH_1=y
CONFIG_LV_THEME_MONO=y
CONFIG_LV_THEME_DEFAULT_INIT_MONO=y
CONFIG_LV_DISP_DEF_REFR_PERIOD=500
CONFIG_LV_TFT_DISPLAY_USER_CONTROLLER_SSD1680=y
CONFIG_LV_HOR_RES_MAX=128
CONFIG_LV_VER_RES_MAX=296
CONFIG_LV_DPI=112
CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE=y
#
# Display Pin Assignments
#
CONFIG_LV_DISP_SPI_MOSI=38
# CONFIG_LV_DISPLAY_USE_SPI_MISO is not set
CONFIG_LV_DISP_SPI_CLK=37
CONFIG_LV_DISPLAY_USE_SPI_CS=y
CONFIG_LV_DISP_SPI_CS=36
CONFIG_LV_DISPLAY_USE_DC=y
CONFIG_LV_DISP_PIN_DC=35
CONFIG_LV_DISP_USE_RST=y
CONFIG_LV_DISP_PIN_RST=34
CONFIG_LV_DISP_PIN_BUSY=33
CONFIG_LV_DISP_BACKLIGHT_OFF=y
Unfortunately I do not have the display anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick reply! Fyi (and for anyone that stumbles on this), in the end, the LVGL buffer needed to be manually set up as it does not cover the entire screen and thus it was rendering only bits and pieces. Also, here is a fixed snipped for landscape mode (you have it backwards :)
// mirrored index
uint16_t mirrored_idx = (EPD_PANEL_HEIGHT - x) + ((y >> 3) * EPD_PANEL_HEIGHT);
byte_index = x + ((y >> 3) * EPD_PANEL_HEIGHT);
bit_index = y & 0x7;
// 1 means white, 0 means black
// note that the bit index is inverted in place
if (color.full == 0) {
BIT_SET(buf[mirrored_idx - 1], 7 - bit_index);
} else {
BIT_CLEAR(buf[mirrored_idx - 1], 7 - bit_index);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for fixing this.
That part was very blurry to me. Obviously I haven't understood it.
Is there a way for you to test it with the fix?
(Or you already have?!)
Thanks to Damian Glinojecki
I need to clean up my base, but once I am done, I can do a pr. This is a weekend/night project so it will take some time. |
Do you have some example code with the initialisation process for the SSD1680? I've been able to drive a classic LCD display with ESP & LVGL and thankfully with your PR been able to compile it for an e-paper, but I'm having trouble displaying anything. |
when initializing |
Hmm, okay. I'm using LVGL v8.3.0 and esp-idf v5 so I had to update few more things, but merging this PR with this one #227 allowed me to compile it all, though nothing ever showed up on the display. And what about lv_disp_drv_init()? I had it for my lcd display. (Sorry, I'm still learning LVGL) :) |
@FilipSzkandera check if this example works for you: |
Yes! Thank you very much, this really helped a lot! |
My code now renders what I want on my e-ink display, however whenever I change anything (i.e. update any part of the screen, change focus, etc) the display won't refresh. It will fill a small portion of the screen with a random garbage, but never goes through the whole refreshing process nor will it change anything else. Have you stumbled upon this at any time? |
Unfortunately no. The issue could be related again to the portrait / landscape mode. However there is something you can try out. Thanks |
Oh! yeah, after x changes the display will appear to be updated correctly! I was not able to confirm that there are 7 needed display updates (I'm not sure when lvgl will force an update) but it is after some amount of button interactions that will change a display contents somehow. Could you please point me somewhere where I could look next? I've done a lot of research and I have ran out of ideas, but should I try to debug your code, or do you think this could be related to something else? |
Good. I believe that the issue should be in the partial flush area. However I lost my display and I cannot test it. Possible workaround could be to avoid the condition and to allow full refresh every time. |
Thank you very much, I'll go through it in upcoming few days and report back if I find anything. |
Ok, now I have dissected every line of your partial-update routine, tried playing with numbers, etc. This change IS NOT a solution, but with this setup, the screen at least appear to be partially changing and I cen see the change happening. But the whole page has offset, the numbers are really faded and funky.
This does eliminate a lot of the "partial update" mechanics, because it updates almost the whole screen. If you would be willing to, I can send you some screenshots, I think with your knowledge and experience you could just see my obvious mistake that I am not seeing (or maybe a bug in the code) :) |
@FilipSzkandera |
@AramVartanyan |
This should be the fix, but I need to run it for longer to be for sure.
|
@FilipSzkandera Thank you for working to fix the issue. The initialization is required no matter if it is a partial or a full refresh. "ssd1680_init();" should stay before the "if(!partial_counter)...". And finally you can try to switch the SSD1680_DATA_ENTRY_XIYIY with SSD1680_DATA_ENTRY_XIYDX for the ssd1680_scan_mode. |
Hello, @FilipSzkandera did you succeed in making your display work with partial update with ESP-IDF 5 and LVGL 8? I'm in the process of porting a little project from arduino+epd2 to ESP-IDF & LVGL, and I'd like to start with the latest stable version of all components. Thanks! |
Yes I did; kinda. To address the previous discussion here, I did end up with this code for void ssd1680_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
/* Each byte holds the data of 8 pixels, linelen is the number of bytes
* we need to cover a line of the display. */
size_t linelen = EPD_PANEL_WIDTH / 8; //SSD1680_COLUMNS = (EPD_PANEL_WIDTH / 8)
uint8_t *buffer = (uint8_t *) color_map;
if (!partial_counter) {
ssd1680_init();
ssd1680_set_cursor(area->y1, area->x1);
ssd1680_send_cmd(SSD1680_CMD_WRITE1_RAM);
for(size_t row = 0; row <= (EPD_PANEL_HEIGHT - 1); row++){
ssd1680_send_data(buffer, linelen);
buffer += SSD1680_COLUMNS;
}
buffer = (uint8_t *) color_map;
ssd1680_send_cmd(SSD1680_CMD_WRITE2_RAM);
for(size_t row = 0; row <= (EPD_PANEL_HEIGHT - 1); row++){
ssd1680_send_data(buffer, linelen);
buffer += SSD1680_COLUMNS;
}
ssd1680_update_display(false);
partial_counter = EPD_PARTIAL_CNT;
} else {
ssd1680_hw_reset();
ssd1680_write_cmd(SSD1680_CMD_BWF_CTRL, ssd1680_border_init, 1);
ssd1680_set_window(area->y1, area->y2, area->x1, area->x2);
ssd1680_set_cursor(area->y1, area->x1);
ssd1680_send_cmd(SSD1680_CMD_WRITE1_RAM);
buffer += (area->x1+8) * area->y1 / 8;
int new_line_len = ((area->y2 - area->y1 + 1)) / 8;
for(size_t row = 0; row <= ((area->x2 - area->x1)); row++) {
ssd1680_send_data(buffer, new_line_len);
buffer += new_line_len; //(128/8)x296 = 4736
}
ssd1680_update_display(true);
partial_counter--;
}
ssd1680_deep_sleep();
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing */
lv_disp_flush_ready(drv);
} Then I had to set LVGL to always refresh the full screen, otherwise this callback won't have the correct data. And it is working great for me ever since. |
No luck, I merged contributes from both driver repositories like you did for both IDF V5- LVGL v8 compatibility and SSD1680 support, but @AramVartanyan test project brings up only a garbled output (pins are set correctly since they work on arduino+epd2). How did you set "LVGL to always refresh the full screen"? @FilipSzkandera . Would you share your setup? drivers and test project? |
Unfortunately the test example works only on LVGL v7.11. I have tried to run v8, but this repository does not support it. It will take lot of effort to make it work. |
The driver module is based on the construction of IL3820 (SSD1608), which is very similar from command point of view.
It is tested on ESP32-S2 MCU and GoodDisplay GDEY029T94.