espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.29k stars 7.2k forks source link

LVGL Font corruption on SSD1306 display (IDFGH-7736) #9277

Open VikOlliver opened 2 years ago

VikOlliver commented 2 years ago

Environment

Problem Description

Default UNSCII fonts are displayed half height when rendered using the stock example code on a 128x32 SSD1306 monochrome OLED display.

Problem is exhibited by other monospace fonts, but the stock examples are probably better for illustrating the bug.

Expected Behavior

UNSCII 8 font displayed 8 pixels high, UNSCII 16 font displayed 16 pixels high

Actual Behavior

UNSCII 8 font displayed 4 pixels high and completely illegible. UNSCII 16 font displayed 8 pixels high, 16 pixels wide.

Steps to reproduce

  1. Set appropriate LVGL UNSCII font in idf.py menuconfig
  2. build/flash esp-idf/examples/peripherals/lcd/i2c_oled

// If possible, attach a picture of your setup/wiring here. Unable to attach. Github reports "something has gone seriously wrong" when attempting to attach a 294KiB JPEG

Code to reproduce this issue

Stock example.

Debug Logs

No errors logged. I (388) cpu_start: Starting scheduler on PRO CPU. I (0) cpu_start: Starting scheduler on APP CPU. I (398) example: Initialize I2C bus I (408) example: Install panel IO I (408) example: Install SSD1306 panel driver I (508) example: Initialize LVGL library I (508) example: Register display driver to LVGL I (508) example: Install LVGL tick timer I (508) example: Display LVGL Scroll Text

VikOlliver commented 2 years ago

font_bug

OK, managed to upload images of the corrupt and squashed font on the OLED display by using Firefox in debug mode :)

VikOlliver commented 2 years ago

Playing with this a bit more, it looks like every other line is missed off everything. Creating a 128x32 text area only puts characters on the top of the screen even when the content scrolls. Expanding it to a 128x64 text box will make it fill the whole screen (as you might see from the pictures above, it's definitely a 128x32 display).

andershedberg commented 2 years ago

[edit - I'm not really sure what example code we have run and put together]

We see some similar behavior as well when we tried out the i2c bus and choose this display we had used in a previous Raspberry Pie project - https://www.adafruit.com/product/3527 [edit - one pull up resistor was not attached, so my remark on 400kHz was not legit. Now it runs at 400 kHz, but still shows strange things]

Is it related to https://github.com/espressif/esp-idf/pull/9209 ? [Edit - the first initial fix in references 9209 does not seem to help. Still strange display.] (there are also a lot of other i2c issues when searching for issues)

VikOlliver commented 2 years ago

I'm not playing with the I2C interface myself, just using the defaults from the esp-idf demo code, and I'm not seeing any other corruption (well, the cursor does temporarily shave the rightmost pixel off the previous character, but that fixes itself eventually). I have done a simple workaround, which is basically just using fontforge to double the height of the font. Not exactly memory-efficient, but functional.

yuanyihan commented 1 year ago

Hi,you can add some code in init():

#if SSD1306_LCD_DISP_IS_128X32 == 1
    esp_lcd_panel_io_tx_param(io_handle, 0xa8, (uint8_t[1]){0x1f}, 1); // 0x3F for 128x64, 0x1F for 128x32
    esp_lcd_panel_io_tx_param(io_handle, 0xda, (uint8_t[1]){0x02}, 1); // 0x12 for 128x64, 0x02 for 128x32
#else
    esp_lcd_panel_io_tx_param(io_handle, 0xa8, (uint8_t[1]){0x3f}, 1); // 0x3F for 128x64, 0x1F for 128x32
    esp_lcd_panel_io_tx_param(io_handle, 0xda, (uint8_t[1]){0x12}, 1); // 0x12 for 128x64, 0x02 for 128x32
#endif

between ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); and ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); in https://github.com/espressif/esp-idf/blob/master/examples/peripherals/lcd/i2c_oled/main/i2c_oled_example_main.c#L126

befor: bef

after: aft

mbelt commented 1 year ago

esp_lcd_panel_init(...) only does the bare minimum setup. Set Addressing Mode0x20 0x00 Enable Charge Pump 0x8D, 0x14 Turn On 0xAF.

The datasheet describes a longer set of initialization steps. (edited 11/7 w/corrections from @yuanyihan) Set MUX Ratio 0xA8, 0x3F for 128x64, 0xA8, 0x1F for 128x32 Set Addressing Mode0x20 0x00 (Not in the datasheet init flowchart, but necessary) Set Display Offset 0xD3, 0x00 Set Display Start Line 0x40, 0x00 Set Segment Re-Map 0xA0 Set COM Output Scan Direction 0xC0 (or 0xC8 for 180° rotation) Set COM Pins Hardware Configuration 0xDA, 0x12 for 128x64 or 0xDA, 0x02 for 128x32px Set Contrast Control 0x8a, 0x7F Disable Display On 0xA4 Set Normal Display 0xA6 Set Osc Frequency 0xD5, 0x80 Enable Charge Pump Regulator 0x8D, 0x14 Display On 0xAF

Note: There are many possible combinations for Mux Ratio, Output Direction, and Pins Configuration.

yuanyihan commented 1 year ago

@mbelt THINKS,It‘s very useful Some minor mistakes:

mbelt commented 1 year ago

@yuanyihan No, thank you. | Set Segment Re-Map 0xA0 for normal or 0xA1 for rotation180 Fixed an issue I was having.

Edited previous comment with corrections.

yuanyihan commented 1 year ago

I mean : Acording SSD1306-DATASHEET

We know :

I think esp_lcd_panel_ssd1306.c @ esp-idf's CODE is very obvious. They use MIRROR in static esp_err_t panel_ssd1306_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)

C8A1 C0A0 C0A1 C8A0

storoj commented 10 months ago

@VikOlliver I had the same issue and I did my best to provide the fix: #12450. Thanks @yuanyihan.