nopnop2002 / esp-idf-ili9340

SPI TFT and XPT2046 touch screen controller driver for esp-idf
MIT License
163 stars 34 forks source link

Often crashing on lcdDrawFillRect #37

Closed samsam4 closed 2 years ago

samsam4 commented 2 years ago

Example: lcdDrawFillRect(&dev, 67, 120, 79, 132, 0); Display is st7735s 80x160

ESP-IDF 4.2.1, your code(esp-idf-ili9340-master) is from 25-5-2021

Any idea what is the problem and how to fix it Thanks

assertion "ret_trans == trans_desc" failed: file "D:/ESP2_8/esp-idf/components/driver/spi_master.c", line 835, function: spi_device_transmit assertion "ret_trans == trans_desc" failed: file " abort() was called at PC 0x4014fc07 on core 0 0x4014fc07: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

Backtrace:0x40088ecb:0x3ffcc840 0x40089575:0x3ffcc860 0x40090456:0x3ffcc880 0x4014fc07:0x3ffcc8f0 0x4010b1d5:0x3ffcc920 0x400d9ccd:0x3ffcc950 0x400d9d05:0x3ffcc9a0 0x400da7b9:0x3ffcc9c0 0x400d90b5:0x3ffcc9f0 0x4008957d:0x3ffcca60 0x40088ecb: panic_abort at D:/ESP2_8/esp-idf/components/esp_system/panic.c:330

0x40089575: esp_system_abort at D:/ESP2_8/esp-idf/components/esp_system/system_api.c:106

0x40090456: abort at D:/ESP2_8/esp-idf/components/newlib/abort.c:46

0x4014fc07: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

0x4010b1d5: spi_device_transmit at D:/ESP2_8/esp-idf/components/driver/spi_master.c:835 (discriminator 1)

0x400d9ccd: spi_master_write_byte at D:\W21\ESP\VS2\scanapp15N\build/../components/ili9340/driver/ili9340.c:106

0x400d9d05: spi_master_write_comm_byte at D:\W21\ESP\VS2\scanapp15N\build/../components/ili9340/driver/ili9340.c:122

0x400da7b9: lcdDrawFillRect at D:\W21\ESP\VS2\scanapp15N\build/../components/ili9340/driver/ili9340.c:624

0x400d90b5: http_get_task at D:\W21\ESP\VS2\scanapp15N\build/../main/http_sntp1.c:215

0x4008957d: vPortTaskWrapper at D:/ESP2_8/esp-idf/components/freertos/xtensa/port.c:143

nopnop2002 commented 2 years ago

This is mine

    while(1) {
        lcdDrawFillRect(&dev, 67, 120, 79, 132, 0);
        WAIT;

        FillTest(&dev, CONFIG_WIDTH, CONFIG_HEIGHT);
        WAIT;
    }

IMG_2161

I'm not using the component version.

Somewhere in your code, you may be corrupting the [dev] area.

samsam4 commented 2 years ago

My guess is the problem is same as mentioned here: https://www.esp32.com/viewtopic.php?t=6780

Tomorrow will perform more tests and will try to narrow the possible source of the problem. In my code I don't manipulate the dev variable once was created and don't use any direct access to this structure except through the original functions that are from your driver API.

Regards

nopnop2002 commented 2 years ago

I read this.

https://www.esp32.com/viewtopic.php?t=6780

To answer the original question: you would place e.g. a mutex around the call instead of a spinlock.

Are you using multiple SPI devices?

samsam4 commented 2 years ago

I am using only one device right now - the spi display (but would consider in a future developments one more device on the same bus if possible - flash mem). Regarding core - all modules I am testing on so far are ESP32 core (ESP32-WROVER-E and ESP32-WROOM).

I could place a debug log for dev variable just before lcdDrawFillRect() call that often rise this problem, so could compare what are the values when pass and when crashes. Any particular recommendation which TFT_t structure members to print out? Thanks

P.S. I dont use multiple spi devices (for now), but use many freertos task which for sure at certain points compete to draw on the display / use the spi driver. From the above link for me this is the most essential parts that my wild guess consider: "You can't use spi_device_transmit() if any transmission is queued with spi_device_queue_trans() but not exectued with spi_device_get_trans_result()."

samsam4 commented 2 years ago

I have added vTaskDelay(100); before the line with lcdDrawFillRect() that sometimes was causing crashes, then crash moved on another line line with lcdDrawChar() where also prepend with same delay and now don't see those crashes (at least didn't happened so far in my limited testing). Isn't this a positive sign that those crashes are coming from overloading transmit requests to the spi driver? Thanks

nopnop2002 commented 2 years ago

If the Host only writes data, the dummy bit workaround and the frequency check can be disabled by setting the bit SPI_DEVICE_NO_DUMMY in the member spi_device_interface_config_t::flags.

When disabled, the output frequency can be 80MHz, even if the GPIO matrix is used.

What happens if You change it as follows?

https://github.com/nopnop2002/esp-idf-ili9340/blob/master/main/ili9340.c#L81

    spi_device_interface_config_t devcfg={
        .clock_speed_hz = SPI_Frequency,
        .spics_io_num = GPIO_CS,
        .queue_size = 7,
    };
samsam4 commented 2 years ago

I disable line with // .flags = SPI_DEVICE_NO_DUMMY, tried both current SPI_MASTER_FREQ_40M and after try and SPI_MASTER_FREQ_80M. Either way crashes at spi_master_init Regards

with SPI_MASTER_FREQ_80M:

I (628) disp_spi.c: Initializing SPIFFS I (728) disp_spi.c: Partition size: total: 896321, used: 87348 I (728) SPIFFS_Directory: d_name=Arial31.fnt d_ino=0 d_type=1 I (728) SPIFFS_Directory: d_name=ArrNar23.fnt d_ino=0 d_type=1 I (738) SPIFFS_Directory: d_name=iconic.fnt d_ino=0 d_type=1 I (738) SPIFFS_Directory: d_name=ILGH16XB.FNT d_ino=0 d_type=1 I (748) SPIFFS_Directory: d_name=ILGH24XB.FNT d_ino=0 d_type=1 I (748) SPIFFS_Directory: d_name=ILGH32XB.FNT d_ino=0 d_type=1 I (758) SPIFFS_Directory: d_name=TwCenMT-C20x12.fnt d_ino=0 d_type=1 I (798) ILI9340: GPIO_CS=-1 I (798) ILI9340: GPIO_DC=4 I (798) ILI9340: GPIO_RESET=-1 I (798) ILI9340: GPIO_BL=-1 E (808) spi_hal: spi_hal_get_clock_conf(70): When work in full-duplex mode at frequency > 26.7MHz, device cannot read correct data. Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode. Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration. Specify SPI_DEVICE_NO_DUMMY to ignore this checking. Then you can output data at higher speed, or read data at your own risk. E (848) spi_master: spi_bus_add_device(360): assigned clock speed not supported assertion "ret==ESP_OK" failed: file "../components/ili9340/driver/ili9340.c", line 89, function: spi_master_init

abort() was called at PC 0x4014fc8f on core 0 0x4014fc8f: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

Backtrace:0x40088ecb:0x3ffba410 0x40089575:0x3ffba430 0x40090456:0x3ffba450 0x4014fc8f:0x3ffba4c0 0x400d9d19:0x3ffba4f0 0x400d8de3:0x3ffba570 0x400d572d:0x3ffba5d0 0x400d401e:0x3ffba5f0 0x4008957d:0x3ffba620 0x40088ecb: panic_abort at D:/ESP2_8/esp-idf/components/esp_system/panic.c:330

0x40089575: esp_system_abort at D:/ESP2_8/esp-idf/components/esp_system/system_api.c:106

0x40090456: abort at D:/ESP2_8/esp-idf/components/newlib/abort.c:46

0x4014fc8f: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

0x400d9d19: spi_master_init at D:\W21\ESP\VS2\scanapp15N\build/../components/ili9340/driver/ili9340.c:89 (discriminator 1)

0x400d8de3: disp_spi_init at D:\W21\ESP\VS2\scanapp15N\build/../main/disp_spi1.c:642 (discriminator 15)

0x400d572d: app_main at D:\W21\ESP\VS2\scanapp15N\build/../main/ss_main.c:156

0x400d401e: main_task at D:/ESP2_8/esp-idf/components/esp32/cpu_start.c:609 (discriminator 2)

0x4008957d: vPortTaskWrapper at D:/ESP2_8/esp-idf/components/freertos/xtensa/port.c:143

============================== with SPI_MASTER_FREQ_40M:

I (628) disp_spi.c: Initializing SPIFFS I (728) disp_spi.c: Partition size: total: 896321, used: 87348 I (728) SPIFFS_Directory: d_name=Arial31.fnt d_ino=0 d_type=1 I (728) SPIFFS_Directory: d_name=ArrNar23.fnt d_ino=0 d_type=1 I (738) SPIFFS_Directory: d_name=iconic.fnt d_ino=0 d_type=1 I (738) SPIFFS_Directory: d_name=ILGH16XB.FNT d_ino=0 d_type=1 I (748) SPIFFS_Directory: d_name=ILGH24XB.FNT d_ino=0 d_type=1 I (748) SPIFFS_Directory: d_name=ILGH32XB.FNT d_ino=0 d_type=1 I (758) SPIFFS_Directory: d_name=TwCenMT-C20x12.fnt d_ino=0 d_type=1 I (798) ILI9340: GPIO_CS=-1 I (798) ILI9340: GPIO_DC=4 I (798) ILI9340: GPIO_RESET=-1 I (798) ILI9340: GPIO_BL=-1 E (808) spi_hal: spi_hal_get_clock_conf(70): When work in full-duplex mode at frequency > 26.7MHz, device cannot read correct data. Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode. Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration. Specify SPI_DEVICE_NO_DUMMY to ignore this checking. Then you can output data at higher speed, or read data at your own risk. E (848) spi_master: spi_bus_add_device(360): assigned clock speed not supported assertion "ret==ESP_OK" failed: file "../components/ili9340/driver/ili9340.c", line 89, function: spi_master_init

abort() was called at PC 0x4014fc93 on core 0 0x4014fc93: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

Backtrace:0x40088ecb:0x3ffba410 0x40089575:0x3ffba430 0x40090456:0x3ffba450 0x4014fc93:0x3ffba4c0 0x400d9d1d:0x3ffba4f0 0x400d8de7:0x3ffba570 0x400d5731:0x3ffba5d0 0x400d4022:0x3ffba5f0 0x4008957d:0x3ffba620 0x40088ecb: panic_abort at D:/ESP2_8/esp-idf/components/esp_system/panic.c:330

0x40089575: esp_system_abort at D:/ESP2_8/esp-idf/components/esp_system/system_api.c:106

0x40090456: abort at D:/ESP2_8/esp-idf/components/newlib/abort.c:46

0x4014fc93: __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)

0x400d9d1d: spi_master_init at D:\W21\ESP\VS2\scanapp15N\build/../components/ili9340/driver/ili9340.c:89 (discriminator 1)

0x400d8de7: disp_spi_init at D:\W21\ESP\VS2\scanapp15N\build/../main/disp_spi1.c:642 (discriminator 15)

0x400d5731: app_main at D:\W21\ESP\VS2\scanapp15N\build/../main/ss_main.c:156

0x400d4022: main_task at D:/ESP2_8/esp-idf/components/esp32/cpu_start.c:609 (discriminator 2)

0x4008957d: vPortTaskWrapper at D:/ESP2_8/esp-idf/components/freertos/xtensa/port.c:143

nopnop2002 commented 2 years ago

Can you update from ESP-IDF 4.2.1 to the latest version?

This is mine.

ESP-IDF version:v4.4-dev-2825-gb63ec47238-dirty
samsam4 commented 2 years ago

This unfortunately I cant do right now, because I spent almost a month until I succeed at least VSC to set working with this version of ESP-IDF. Now I am waiting the Espresiff's Eclipse team to publish fixes for all the bugs reported 5 months ago and as soon this happen and if it is at acceptable level, then could update ESP-IDF. Else will become same nightmare that I already had with so many bugs in VSC Extension and Eclipse Plugin :(
If I change the ESP-IDF will have to start all the tests / tracing from very beginning, instead if I keep current version (with which bugs were reported and thoroughly documented) will be easier to check / compare if the new upcoming fixes do the job or not. Will keep you posted when I am able to update ESP-IDF or if meanwhile find a better way to bypass those crashes than with vTaskDelay-s. Now crashes are not so often and I could work on the other parts of the program that still have to done. Regards

nopnop2002 commented 2 years ago

I don't know the exact maximum queue_size, but what if you increase it?

https://github.com/nopnop2002/esp-idf-ili9340/blob/master/main/ili9340.c#L84


What if you use spi_device_polling_transmit() instead of spi_device_transmit()?

https://github.com/nopnop2002/esp-idf-ili9340/blob/master/main/ili9340.c#L111

spi_device_transmit() is interrupt transaction.

spi_device_polling_transmit() is polling transaction.

samsam4 commented 2 years ago

I just took a look at SPI Master driver documentation and seems here is the reason for those crashes:

Warning The SPI master driver has the concept of multiple Devices connected to a single bus (sharing a single ESP32 SPI peripheral). As long as each Device is accessed by only one task, the driver is thread safe. However, if multiple tasks try to access the same SPI Device, the driver is not thread-safe. In this case, it is recommended to either: Refactor your application so that each SPI peripheral is only accessed by a single task at a time. Add a mutex lock around the shared Device using xSemaphoreCreateMutex.

So will have to figure how to refactor my code :(

nopnop2002 commented 2 years ago

if multiple tasks try to access the same SPI Device, the driver is not thread-safe.

If multiple tasks need to access the same SPI device, they must be exclusively controlled using a mutex.

xSemaphoreTake()

xSemaphoreGive()

samsam4 commented 2 years ago

Solved with xSemaphoreCreateMutex. Now I'm wondering only if xSemaphoreCreateMutexStatic isn't the better choice ;) - will put in my TODO list to read and research which would be the better option Thank you for the help and good discussion! Best regards