Trying to run LVGL8 on ESP32-S2 with ST7789 and platformio, CS pin not pulled low during SPI transactions


I have started a new project with ESP32-S2 and a small ST7789 display with 240x135px resolution. Kept everything rather simple so far, made a few minor changes to the esp32 port run with V8 and on esp32-s2, nothing critical, setting up platformio was the biggest hurdle, but got that sorted as well everyting compiles and uploads fine, logs via serial are as expected. Triple checked schematics and IO numbers, all pins have pull-ups (except led backlight which is pulled down).

It seems I am running into some issues with the SPI bus and CS. I have scoped it out and found that the CS pin is only low during setup, but not during the actual SPI transaction as can be seen in this screenshot from my scope:

1: MOSI (yellow)
2: CLK (light blue)
3: CS (pink)
4: DC/RS (not reset) (dark blue)

I have uploaded the code to a github repo:
It is a VSCode/PlatformIO project.

I have spent quite some time trying to find out why it does this trying to understand the low level spi code in the driver, but have not found any issues. From what I see the CS pin should be pulled low during transactions by the spi interface, at least everything seems to be configured correctly.

An clues about why I am seeing this kind of behavior?
thank you!

all spi transactions should be done in flush_cb, please check with it.

All spi transactions except setup are in flush_cb. As mentioned, all the code is based on the esp32 port, only I am not running any demos but just place a centered label and white background to keep things extra simple. I am triggering the scope when CS is pulled low. The screen stays black (with backlight confirmed on) which not surprising since CS is high when MOSI and CLK are busy, hence I felt inclined posting it here (including the sample code as seen in the linked github repo).

It looks like something bad happens here, are you sure that you give that sem every 10ms?

/* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {

Make sure that lv_task_handle() called repeatedly.

turok, i appreciate your input, but you are not looking at the right place in regards to my problem. Apart from this the code you are referencing is 1:1 from the official esp32 port that I have linked to in the previous post, which is also not giving the semaphore every 10 seconds, but is taking it with a timeout of portMAX_DELAY, and once it has the semaphore it is calling the task handler and then gives the semaphore.

My problem occurs at the initialization, as already the very first SPI transaction does not have CS pulled low. That should be happening in lvgl_driver_init(); in main.c on line 69

I actually found out about the problem because my scope would not trigger on SPI at all because CS was never low during transactions, I knew however that there were spi transactions because triggering on MOSI or CLK worked fine.

FYI, if I am right, a timeout of portMAX_DELAY will be a very long period.
What did you get when initial LCD without lvgl setups?
Take care with esp32 module s that some share spi signals with code flash communications.

FYI, if I am right, a timeout of portMAX_DELAY will be a very long period.

yes it is but it does not matter at all because nothing else in the code is taking the semaphore. and even if something else took it, it would only matter if it would keep the semaphore, which would be an entirely different problem.

What did you get when initial LCD without lvgl setups?

You mean without lv_init()? Why do you think that would make a difference? The problem I am trying to solve is why my CS line stays high during SPI transactions, because the display wont do anything without CS going low during SPI transactions …

Take care with esp32 module s that some share spi signals with code flash communications.

I am using a custom board with an ESP32-S2FH4 SoC (integrated 4mb) and I carefuly chose the displays SPI pins by consulting the datasheet and integration manual to make sure they are not used by anything else. The display is driven by pins 33-38, detailed pinmap is in platformio.ini.

something maybe worth noting is, I just tried manually pulling CS to ground while undefining CONFIG_LV_DISPLAY_USE_SPI_CS and it simply would not affect how the scope output looks like. If I manually control the DC pin I see toggling it on the scope, but I wont see any changes on the CS pin :thinking:

What I mean is that test your driver before using the library, make sure it works well, and then try to link into the library.

yeah you know turok, this is kind of the whole point about posting here. the driver is the official lvgl esp32 driver, and I am posting here hoping to get help to get it to work, as it is kind of apparent that the driver is not working on my esp32-s2 implementation. :man_shrugging:

Edit: Really, this is all about the most basic lvgl implementation using the lvgl drivers as officially provided by lvgl – just on an esp32-S2. There is no point in leaving out lvgl here as then the driver would not do anything anymore …

I have found the mistake :joy:
Can you spot it?

Fortunately it only took days to find instead of weeks. :man_facepalming:

I did check the schematic many times, reread the datasheet and all, I just never looked at where two hierachial sheets connected as it is the most simple part of the schematic, right? What made it additionally hard to find was the fact the S2 still has a bunch of hurdles that the original ESP32 has not, for instance there was a bug that just got fixed last week that would kill wifi if you used and ADC. So instead of looking at the simplest connections in my schematic I was looking for flaws in the ESP32-S2 … :man_shrugging:

Hmm one more issue, I actually thought I have just inverted hor/vert display size, but swapping it has no effect. any ideas?

So I just came back to this problem after letting it rest for a while. I’ve tried shifting the offsets in st7789_flush() according to what Kconfig sets for the TTGO display (which is equivalent to what I use) but it seems what the photo in the post above shows is the closest to where I get to what the actual display should look like :frowning:

I’m essentially trying this while swapping values for x and y:

offsetx1 += 53;
offsetx2 += 53;
offsety1 += 40;
offsety2 += 40;

but this resorted only in some random white pixels.

Has anybody seen this symptom before and has some hints on how to fix it? :pray: